1// jquery.daterangepicker.js 2// author : Chunlong Liu 3// license : MIT 4// www.jszen.com 5 6(function (factory) { 7 if (typeof define === 'function' && define.amd) { 8 // AMD. Register as an anonymous module. 9 define(['jquery', 'moment'], factory); 10 } else if (typeof exports === 'object' && typeof module !== 'undefined') { 11 // CommonJS. Register as a module 12 module.exports = factory(require('jquery'), require('moment')); 13 } else { 14 // Browser globals 15 factory(jQuery, moment); 16 } 17}(function ($, moment) 18{ 19 'use strict'; 20 $.dateRangePickerLanguages = 21 { 22 'default': //default language: English 23 { 24 'selected': 'Selected:', 25 'day':'Day', 26 'days': 'Days', 27 'apply': 'Close', 28 'week-1' : 'mo', 29 'week-2' : 'tu', 30 'week-3' : 'we', 31 'week-4' : 'th', 32 'week-5' : 'fr', 33 'week-6' : 'sa', 34 'week-7' : 'su', 35 'week-number': 'W', 36 'month-name': ['january','february','march','april','may','june','july','august','september','october','november','december'], 37 'shortcuts' : 'Shortcuts', 38 'custom-values': 'Custom Values', 39 'past': 'Past', 40 'following':'Following', 41 'previous' : 'Previous', 42 'prev-week' : 'Week', 43 'prev-month' : 'Month', 44 'prev-year' : 'Year', 45 'next':'Next', 46 'next-week':'Week', 47 'next-month':'Month', 48 'next-year':'Year', 49 'less-than' : 'Date range should not be more than %d days', 50 'more-than' : 'Date range should not be less than %d days', 51 'default-more' : 'Please select a date range longer than %d days', 52 'default-single' : 'Please select a date', 53 'default-less' : 'Please select a date range less than %d days', 54 'default-range' : 'Please select a date range between %d and %d days', 55 'default-default': 'Please select a date range', 56 'time':'Time', 57 'hour':'Hour', 58 'minute':'Minute' 59 }, 60 }; 61 62 $.fn.dateRangePicker = function(opt) 63 { 64 if (!opt) opt = {}; 65 opt = $.extend(true, 66 { 67 autoClose: false, 68 format: 'YYYY-MM-DD', 69 separator: ' to ', 70 language: 'auto', 71 startOfWeek: 'sunday',// or monday 72 getValue: function() 73 { 74 return $(this).val(); 75 }, 76 setValue: function(s) 77 { 78 if(!$(this).attr('readonly') && !$(this).is(':disabled') && s != $(this).val()) 79 { 80 $(this).val(s); 81 } 82 }, 83 startDate: false, 84 endDate: false, 85 time: { 86 enabled: false 87 }, 88 minDays: 0, 89 maxDays: 0, 90 showShortcuts: false, 91 shortcuts: 92 { 93 //'prev-days': [1,3,5,7], 94 // 'next-days': [3,5,7], 95 //'prev' : ['week','month','year'], 96 // 'next' : ['week','month','year'] 97 }, 98 customShortcuts : [], 99 inline:false, 100 container:'body', 101 alwaysOpen:false, 102 singleDate:false, 103 lookBehind: false, 104 batchMode: false, 105 duration: 200, 106 stickyMonths: false, 107 dayDivAttrs: [], 108 dayTdAttrs: [], 109 selectForward: false, 110 selectBackward: false, 111 applyBtnClass: '', 112 singleMonth: 'auto', 113 hoveringTooltip: function(days, startTime, hoveringTime) 114 { 115 return days > 1 ? days + ' ' + lang('days') : ''; 116 }, 117 showTopbar: true, 118 swapTime: false, 119 showWeekNumbers: false, 120 getWeekNumber: function(date) //date will be the first day of a week 121 { 122 return moment(date).format('w'); 123 }, 124 customOpenAnimation: null, 125 customCloseAnimation: null 126 },opt); 127 128 opt.start = false; 129 opt.end = false; 130 131 opt.startWeek = false; 132 133 //detect a touch device 134 opt.isTouchDevice = 'ontouchstart' in window || navigator.msMaxTouchPoints; 135 136 //if it is a touch device, hide hovering tooltip 137 if (opt.isTouchDevice) opt.hoveringTooltip = false; 138 139 //show one month on mobile devices 140 if (opt.singleMonth == 'auto') opt.singleMonth = $(window).width() < 480; 141 if (opt.singleMonth) opt.stickyMonths = false; 142 143 if (!opt.showTopbar) opt.autoClose = true; 144 145 if (opt.startDate && typeof opt.startDate == 'string') opt.startDate = moment(opt.startDate,opt.format).toDate(); 146 if (opt.endDate && typeof opt.endDate == 'string') opt.endDate = moment(opt.endDate,opt.format).toDate(); 147 148 var langs = getLanguages(); 149 var box; 150 var initiated = false; 151 var self = this; 152 var selfDom = $(self).get(0); 153 var domChangeTimer; 154 155 $(this).unbind('.datepicker').bind('click.datepicker',function(evt) 156 { 157 var isOpen = box.is(':visible'); 158 if(!isOpen) open(opt.duration); 159 }).bind('change.datepicker', function(evt) 160 { 161 checkAndSetDefaultValue(); 162 }).bind('keyup.datepicker',function() 163 { 164 try{ clearTimeout(domChangeTimer); }catch(e){} 165 domChangeTimer = setTimeout(function() 166 { 167 checkAndSetDefaultValue(); 168 },2000); 169 }); 170 171 init_datepicker.call(this); 172 173 if (opt.alwaysOpen) 174 { 175 open(0); 176 } 177 178 // expose some api 179 $(this).data('dateRangePicker', 180 { 181 setDateRange : function(d1,d2,silent) 182 { 183 if (typeof d1 == 'string' && typeof d2 == 'string') 184 { 185 d1 = moment(d1,opt.format).toDate(); 186 d2 = moment(d2,opt.format).toDate(); 187 } 188 setDateRange(d1,d2,silent); 189 }, 190 clear: clearSelection, 191 close: closeDatePicker, 192 open: open, 193 redraw: redrawDatePicker, 194 getDatePicker: getDatePicker, 195 resetMonthsView: resetMonthsView, 196 destroy: function() 197 { 198 $(self).unbind('.datepicker'); 199 $(self).data('dateRangePicker',''); 200 $(self).data('date-picker-opened',null); 201 box.remove(); 202 $(window).unbind('resize.datepicker',calcPosition); 203 $(document).unbind('click.datepicker',closeDatePicker); 204 } 205 }); 206 207 $(window).bind('resize.datepicker',calcPosition); 208 209 return this; 210 211 function IsOwnDatePickerClicked(evt, selfObj) 212 { 213 return ( selfObj.contains(evt.target) || evt.target == selfObj || (selfObj.childNodes != undefined && $.inArray(evt.target, selfObj.childNodes)>=0)); 214 } 215 216 function init_datepicker() 217 { 218 var self = this; 219 220 if ($(this).data('date-picker-opened')) 221 { 222 closeDatePicker(); 223 return; 224 } 225 $(this).data('date-picker-opened',true); 226 227 228 box = createDom().hide(); 229 box.append('<div class="date-range-length-tip"></div>'); 230 box.delegate('.day', 'mouseleave', function() 231 { 232 box.find('.date-range-length-tip').hide(); 233 if (opt.singleDate) { 234 clearHovering(); 235 } 236 }); 237 238 $(opt.container).append(box); 239 240 if (!opt.inline) 241 { 242 calcPosition(); 243 } 244 else 245 { 246 box.addClass('inline-wrapper'); 247 } 248 249 if (opt.alwaysOpen) 250 { 251 box.find('.apply-btn').hide(); 252 } 253 254 var defaultTime = getDefaultTime(); 255 resetMonthsView(defaultTime); 256 257 if (opt.time.enabled) 258 { 259 if ((opt.startDate && opt.endDate) || (opt.start && opt.end)) { 260 showTime(moment(opt.start || opt.startDate).toDate(),'time1'); 261 showTime(moment(opt.end || opt.endDate).toDate(),'time2'); 262 } else { 263 var defaultEndTime = opt.defaultEndTime ? opt.defaultEndTime : defaultTime; 264 showTime(defaultTime,'time1'); 265 showTime(defaultEndTime,'time2'); 266 } 267 } 268 269 //showSelectedInfo(); 270 271 272 var defaultTopText = ''; 273 if (opt.singleDate) 274 defaultTopText = lang('default-single'); 275 else if (opt.minDays && opt.maxDays) 276 defaultTopText = lang('default-range'); 277 else if (opt.minDays) 278 defaultTopText = lang('default-more'); 279 else if (opt.maxDays) 280 defaultTopText = lang('default-less'); 281 else 282 defaultTopText = lang('default-default'); 283 284 box.find('.default-top').html( defaultTopText.replace(/\%d/,opt.minDays).replace(/\%d/,opt.maxDays)); 285 if (opt.singleMonth) 286 { 287 box.addClass('single-month'); 288 } 289 else 290 { 291 box.addClass('two-months'); 292 } 293 294 295 setTimeout(function() 296 { 297 updateCalendarWidth(); 298 initiated = true; 299 },0); 300 301 box.click(function(evt) 302 { 303 evt.stopPropagation(); 304 }); 305 306 //if user click other place of the webpage, close date range picker window 307 $(document).bind('click.datepicker',function(evt) 308 { 309 if (!IsOwnDatePickerClicked(evt, self[0])) { 310 if (box.is(':visible')) closeDatePicker(); 311 } 312 }); 313 314 box.find('.next').click(function() 315 { 316 if(!opt.stickyMonths) 317 gotoNextMonth(this); 318 else 319 gotoNextMonth_stickily(this); 320 }); 321 322 function gotoNextMonth(self) 323 { 324 var isMonth2 = $(self).parents('table').hasClass('month2');
325 var month = isMonth2 ? opt.month2 : opt.month1; 326 month = nextMonth(month); 327 if (!opt.singleMonth && !opt.singleDate && !isMonth2 && compare_month(month,opt.month2) >= 0 || isMonthOutOfBounds(month)) return; 328 showMonth(month,isMonth2 ? 'month2' : 'month1'); 329 showGap(); 330 } 331 332 function gotoNextMonth_stickily(self) { 333 var nextMonth1 = nextMonth(opt.month1); 334 var nextMonth2 = nextMonth(opt.month2); 335 if(isMonthOutOfBounds(nextMonth2)) return; 336 if (!opt.singleDate && compare_month(nextMonth1,nextMonth2) >= 0) return; 337 showMonth(nextMonth1, 'month1'); 338 showMonth(nextMonth2, 'month2'); 339 showSelectedDays(); 340 } 341 342 343 box.find('.prev').click(function() 344 { 345 if(!opt.stickyMonths) 346 gotoPrevMonth(this); 347 else 348 gotoPrevMonth_stickily(this); 349 }); 350 351 function gotoPrevMonth(self) { 352 var isMonth2 = $(self).parents('table').hasClass('month2'); 353 var month = isMonth2 ? opt.month2 : opt.month1; 354 month = prevMonth(month); 355 if (isMonth2 && compare_month(month,opt.month1) <= 0 || isMonthOutOfBounds(month)) return; 356 showMonth(month,isMonth2 ? 'month2' : 'month1'); 357 showGap(); 358 } 359 360 function gotoPrevMonth_stickily(self) 361 { 362 var prevMonth1 = prevMonth(opt.month1); 363 var prevMonth2 = prevMonth(opt.month2); 364 if(isMonthOutOfBounds(prevMonth1)) return; 365 if(!opt.singleDate && compare_month(prevMonth2,prevMonth1) <= 0) return; 366 showMonth(prevMonth2, 'month2'); 367 showMonth(prevMonth1, 'month1'); 368 showSelectedDays(); 369 } 370 371 box.delegate('.day','click', function(evt) 372 { 373 dayClicked($(this)); 374 }); 375 376 box.delegate('.day','mouseenter',function(evt) 377 { 378 dayHovering($(this)); 379 }); 380 381 box.delegate('.week-number', 'click', function(evt) 382 { 383 weekNumberClicked($(this)); 384 }); 385 386 box.attr('unselectable', 'on') 387 .css('user-select', 'none') 388 .bind('selectstart', function(e) 389 { 390 e.preventDefault(); return false; 391 }); 392 393 box.find('.apply-btn').click(function() 394 { 395 closeDatePicker(); 396 var dateRange = getDateString(new Date(opt.start))+ opt.separator +getDateString(new Date(opt.end)); 397 $(self).trigger('datepicker-apply', 398 { 399 'value': dateRange, 400 'date1' : new Date(opt.start), 401 'date2' : new Date(opt.end) 402 }); 403 }); 404 405 box.find('[custom]').click(function() 406 { 407 var valueName = $(this).attr('custom'); 408 opt.start = false; 409 opt.end = false; 410 box.find('.day.checked').removeClass('checked'); 411 opt.setValue.call(selfDom, valueName); 412 checkSelectionValid(); 413 showSelectedInfo(true); 414 showSelectedDays(); 415 if (opt.autoClose) closeDatePicker(); 416 }); 417 418 box.find('[shortcut]').click(function() 419 { 420 var shortcut = $(this).attr('shortcut'); 421 var end = new Date(),start = false; 422 var dir; 423 if (shortcut.indexOf('day') != -1) 424 { 425 var day = parseInt(shortcut.split(',',2)[1],10); 426 start = new Date(new Date().getTime() + 86400000*day); 427 end = new Date(end.getTime() + 86400000*(day>0?1:-1) ); 428 } 429 else if (shortcut.indexOf('week')!= -1) 430 { 431 dir = shortcut.indexOf('prev,') != -1 ? -1 : 1; 432 var stopDay; 433 if (dir == 1) 434 stopDay = opt.startOfWeek == 'monday' ? 1 : 0; 435 else 436 stopDay = opt.startOfWeek == 'monday' ? 0 : 6; 437 438 end = new Date(end.getTime() - 86400000); 439 while(end.getDay() != stopDay) end = new Date(end.getTime() + dir*86400000); 440 start = new Date(end.getTime() + dir*86400000*6); 441 } 442 else if (shortcut.indexOf('month') != -1) 443 { 444 dir = shortcut.indexOf('prev,') != -1 ? -1 : 1; 445 if (dir == 1) 446 start = nextMonth(end); 447 else 448 start = prevMonth(end); 449 start.setDate(1); 450 end = nextMonth(start); 451 end.setDate(1); 452 end = new Date(end.getTime() - 86400000); 453 } 454 else if (shortcut.indexOf('year') != -1) 455 { 456 dir = shortcut.indexOf('prev,') != -1 ? -1 : 1; 457 start = new Date(); 458 start.setFullYear(end.getFullYear() + dir); 459 start.setMonth(0); 460 start.setDate(1); 461 end.setFullYear(end.getFullYear() + dir); 462 end.setMonth(11); 463 end.setDate(31); 464 } 465 else if (shortcut == 'custom') 466 { 467 var name = $(this).html(); 468 if (opt.customShortcuts && opt.customShortcuts.length > 0) 469 { 470 for(var i=0;i<opt.customShortcuts.length;i++) 471 { 472 var sh = opt.customShortcuts[i]; 473 if (sh.name == name) 474 { 475 var data = []; 476 // try 477 // { 478 data = sh['dates'].call(); 479 //}catch(e){} 480 if (data && data.length == 2) 481 { 482 start = data[0]; 483 end = data[1]; 484 } 485 486 // if only one date is specified then just move calendars there 487 // move calendars to show this date's month and next months 488 if (data && data.length == 1) 489 { 490 var movetodate = data[0]; 491 showMonth(movetodate,'month1'); 492 showMonth(nextMonth(movetodate),'month2'); 493 showGap(); 494 } 495 496 break; 497 } 498 } 499 } 500 } 501 if (start && end) 502 { 503 setDateRange(start,end); 504 checkSelectionValid(); 505 } 506 }); 507 508 box.find('.time1 input[type=range]').bind('change touchmove mousemove', function (e) { 509 var target = e.target, 510 hour = target.name == 'hour' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined, 511 min = target.name == 'minute' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined; 512 setTime('time1', hour, min); 513 }); 514 515 box.find('.time2 input[type=range]').bind('change touchmove mousemove', function (e) { 516 var target = e.target, 517 hour = target.name == 'hour' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined, 518 min = target.name == 'minute' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined; 519 setTime('time2', hour, min); 520 }); 521 522 } 523 524 525 function calcPosition() 526 { 527 if (!opt.inline) 528 { 529 var offset = $(self).offset(); 530 if ($(opt.container).css('position') == 'relative') 531 { 532 var containerOffset = $(opt.container).offset(); 533 box.css( 534 { 535 top: offset.top - containerOffset.top + $(self).outerHeight() + 4, 536 left: offset.left - containerOffset.left 537 });
538 } 539 else 540 { 541 if (offset.left < 460) //left to right 542 { 543 box.css( 544 { 545 top: offset.top+$(self).outerHeight() + parseInt($('body').css('border-top') || 0,10 ), 546 left: offset.left 547 }); 548 } 549 else 550 { 551 box.css( 552 { 553 top: offset.top+$(self).outerHeight() + parseInt($('body').css('border-top') || 0,10 ), 554 left: offset.left + $(self).width() - box.width() - 16 555 }); 556 } 557 } 558 } 559 } 560 561 // Return the date picker wrapper element 562 function getDatePicker() 563 { 564 return box; 565 } 566 567 function open(animationTime) 568 { 569 calcPosition(); 570 redrawDatePicker(); 571 checkAndSetDefaultValue(); 572 if (opt.customOpenAnimation) 573 { 574 opt.customOpenAnimation.call(box.get(0), function() 575 { 576 $(self).trigger('datepicker-opened', {relatedTarget: box}); 577 }); 578 } 579 else 580 { 581 box.slideDown(animationTime, function(){ 582 $(self).trigger('datepicker-opened', {relatedTarget: box}); 583 }); 584 } 585 $(self).trigger('datepicker-open', {relatedTarget: box}); 586 showGap(); 587 updateCalendarWidth(); 588 } 589 590 function checkAndSetDefaultValue() 591 { 592 var __default_string = opt.getValue.call(selfDom); 593 var defaults = __default_string ? __default_string.split( opt.separator ) : ''; 594 595 if (defaults && ((defaults.length==1 && opt.singleDate) || defaults.length>=2)) 596 { 597 var ___format = opt.format; 598 if (___format.match(/Do/)) 599 { 600 601 ___format = ___format.replace(/Do/,'D'); 602 defaults[0] = defaults[0].replace(/(\d+)(th|nd|st)/,'$1'); 603 if(defaults.length >= 2){ 604 defaults[1] = defaults[1].replace(/(\d+)(th|nd|st)/,'$1'); 605 } 606 } 607 // set initiated to avoid triggerring datepicker-change event 608 initiated = false; 609 if(defaults.length >= 2){ 610 setDateRange(getValidValue(defaults[0], ___format, moment.locale(opt.language)),getValidValue(defaults[1], ___format, moment.locale(opt.language))); 611 } 612 else if(defaults.length==1 && opt.singleDate){ 613 setSingleDate(getValidValue(defaults[0], ___format, moment.locale(opt.language))); 614 } 615 616 initiated = true; 617 } 618 } 619 620 function getValidValue(date, format, locale) { 621 if (moment(date, format, locale).isValid()) { 622 return moment(date, format, locale).toDate(); 623 } else { 624 return moment().toDate(); 625 } 626 } 627 628 function updateCalendarWidth() 629 { 630 var gapMargin = box.find('.gap').css('margin-left'); 631 if (gapMargin) gapMargin = parseInt(gapMargin); 632 var w1 = box.find('.month1').width(); 633 var w2 = box.find('.gap').width() + ( gapMargin ? gapMargin*2 : 0 ); 634 var w3 = box.find('.month2').width(); 635 box.find('.month-wrapper').width(w1 + w2 + w3); 636 } 637 638 function renderTime (name, date) { 639 box.find('.' + name + ' input[type=range].hour-range').val(moment(date).hours()); 640 box.find('.' + name + ' input[type=range].minute-range').val(moment(date).minutes()); 641 setTime(name, moment(date).format('HH'), moment(date).format('mm')); 642 } 643 644 function changeTime (name, date) { 645 opt[name] = parseInt( 646 moment(parseInt(date)) 647 .startOf('day') 648 .add(moment(opt[name + 'Time']).format('HH'), 'h') 649 .add(moment(opt[name + 'Time']).format('mm'), 'm').valueOf() 650 ); 651 } 652 653 function swapTime () { 654 renderTime('time1', opt.start); 655 renderTime('time2', opt.end); 656 } 657 658 function setTime (name, hour, minute) 659 { 660 hour && (box.find('.' + name + ' .hour-val').text(hour)); 661 minute && (box.find('.' + name + ' .minute-val').text(minute)); 662 switch (name) { 663 case 'time1': 664 if (opt.start) { 665 setRange('start', moment(opt.start)); 666 } 667 setRange('startTime', moment(opt.startTime || moment().valueOf())); 668 break; 669 case 'time2': 670 if (opt.end) { 671 setRange('end', moment(opt.end)); 672 } 673 setRange('endTime', moment(opt.endTime || moment().valueOf())); 674 break; 675 } 676 function setRange(name, timePoint) { 677 var h = timePoint.format('HH'), 678 m = timePoint.format('mm'); 679 opt[name] = timePoint 680 .startOf('day') 681 .add(hour || h, 'h') 682 .add(minute || m, 'm') 683 .valueOf(); 684 } 685 checkSelectionValid(); 686 showSelectedInfo(); 687 showSelectedDays(); 688 } 689 690 function clearSelection() 691 { 692 opt.start = false; 693 opt.end = false; 694 box.find('.day.checked').removeClass('checked'); 695 box.find('.day.last-date-selected').removeClass('last-date-selected'); 696 box.find('.day.first-date-selected').removeClass('first-date-selected'); 697 opt.setValue.call(selfDom, ''); 698 checkSelectionValid(); 699 showSelectedInfo(); 700 showSelectedDays(); 701 } 702 703 function handleStart(time) 704 { 705 var r = time; 706 if (opt.batchMode === 'week-range') 707 { 708 if (opt.startOfWeek === 'monday') 709 { 710 r = moment(parseInt(time)).startOf('isoweek').valueOf(); 711 } 712 else 713 { 714 r = moment(parseInt(time)).startOf('week').valueOf(); 715 } 716 } 717 else if (opt.batchMode === 'month-range') 718 { 719 r = moment(parseInt(time)).startOf('month').valueOf(); 720 } 721 return r; 722 } 723 724 function handleEnd(time) 725 { 726 var r = time; 727 if (opt.batchMode === 'week-range') 728 { 729 if (opt.startOfWeek === 'monday') 730 { 731 r = moment(parseInt(time)).endOf('isoweek').valueOf(); 732 } 733 else 734 { 735 r = moment(parseInt(time)).endOf('week').valueOf(); 736 } 737 } 738 else if (opt.batchMode === 'month-range') 739 { 740 r = moment(parseInt(time)).endOf('month').valueOf(); 741 } 742 return r; 743 } 744 745 746 function dayClicked(day) 747 { 748 if (day.hasClass('invalid')) return; 749 var time = day.attr('time'); 750 day.addClass('checked'); 751 if ( opt.singleDate ) 752 { 753 opt.start = time; 754 opt.end = false; 755 } 756 else if (opt.batchMode === 'week') 757 { 758 if (opt.startOfWeek === 'monday') { 759 opt.start = moment(parseInt(time)).startOf('isoweek').valueOf(); 760 opt.end = moment(parseInt(time)).endOf('isoweek').valueOf(); 761 } else { 762 opt.end = moment(parseInt(time)).endOf('week').valueOf(); 763 opt.start = moment(parseInt(time)).startOf('week').valueOf(); 764 } 765 } 766 else if (opt.batchMode === 'workweek') 767 { 768 opt.start = moment(parseInt(time)).day(1).valueOf(); 769 opt.end = moment(parseInt(time)).day(5).valueOf(); 770 } 771 else if (opt.batchMode === 'weekend') 772 { 773 opt.start = moment(parseInt(time)).day(6).valueOf(); 774 opt.end = moment(parseInt(time)).day(7).valueOf(); 775 } 776 else if (opt.batchMode === 'month') 777 { 778 opt.start = moment(parseInt(time)).startOf('month').valueOf(); 779 opt.end = moment(parseInt(time)).endOf('month').valueOf(); 780 } 781 else if ((opt.start && opt.end) || (!opt.start && !opt.end) ) 782 { 783 opt.start = handleStart(time); 784 opt.end = false; 785 } 786 else if (opt.start) 787 { 788 opt.end = handleEnd(time); 789 if (opt.time.enabled) { 790 changeTime('end', opt.end); 791 } 792 } 793 794 //Update time in case it is enabled and timestamps are available 795 if(opt.time.enabled) { 796 if(opt.start) { 797 changeTime('start', opt.start); 798 } 799 if(opt.end) { 800 changeTime('end', opt.end); 801 } 802 } 803 804 //In case the start is after the end, swap the timestamps 805 if (!opt.singleDate && opt.start && opt.end && opt.start > opt.end) 806 { 807 var tmp = opt.end; 808 opt.end = handleEnd(opt.start); 809 opt.start = handleStart(tmp); 810 if (opt.time.enabled && opt.swapTime) { 811 swapTime(); 812 } 813 } 814 815 opt.start = parseInt(opt.start); 816 opt.end = parseInt(opt.end); 817 818 clearHovering(); 819 if (opt.start && !opt.end) 820 { 821 $(self).trigger('datepicker-first-date-selected', 822 { 823 'date1' : new Date(opt.start) 824 }); 825 dayHovering(day); 826 } 827 updateSelectableRange(time); 828 829 checkSelectionValid(); 830 showSelectedInfo(); 831 showSelectedDays(); 832 autoclose(); 833 } 834 835 836 function weekNumberClicked(weekNumberDom) 837 { 838 var thisTime = parseInt(weekNumberDom.attr('data-start-time'),10); 839 var date1,date2; 840 if (!opt.startWeek) 841 { 842 opt.startWeek = thisTime; 843 weekNumberDom.addClass('week-number-selected'); 844 date1 = new Date(thisTime); 845 opt.start = moment(date1).day(opt.startOfWeek == 'monday' ? 1 : 0).valueOf(); 846 opt.end = moment(date1).day(opt.startOfWeek == 'monday' ? 7 : 6).valueOf(); 847 } 848 else 849 { 850 box.find('.week-number-selected').removeClass('week-number-selected'); 851 date1 = new Date(thisTime < opt.startWeek ? thisTime : opt.startWeek); 852 date2 = new Date(thisTime < opt.startWeek ? opt.startWeek : thisTime); 853 opt.startWeek = false; 854 opt.start = moment(date1).day(opt.startOfWeek == 'monday' ? 1 : 0).valueOf(); 855 opt.end = moment(date2).day(opt.startOfWeek == 'monday' ? 7 : 6).valueOf(); 856 } 857 updateSelectableRange(); 858 checkSelectionValid(); 859 showSelectedInfo(); 860 showSelectedDays(); 861 autoclose(); 862 } 863 864 function isValidTime(time) 865 { 866 time = parseInt(time, 10); 867 if (opt.startDate && compare_day(time, opt.startDate) < 0) return false;
868 if (opt.endDate && compare_day(time, opt.endDate) > 0) return false; 869 870 if (opt.start && !opt.end && !opt.singleDate) 871 { 872 //check maxDays and minDays setting 873 if (opt.maxDays > 0 && countDays(time, opt.start) > opt.maxDays) return false; 874 if (opt.minDays > 0 && countDays(time, opt.start) < opt.minDays) return false; 875 876 //check selectForward and selectBackward 877 if (opt.selectForward && time < opt.start ) return false; 878 if (opt.selectBackward && time > opt.start) return false; 879 880 //check disabled days 881 if (opt.beforeShowDay && typeof opt.beforeShowDay == 'function') 882 { 883 var valid = true; 884 var timeTmp = time; 885 while( countDays(timeTmp, opt.start) > 1 ) 886 { 887 var arr = opt.beforeShowDay( new Date(timeTmp) ); 888 if (!arr[0]) 889 { 890 valid = false; 891 break; 892 } 893 if (Math.abs(timeTmp - opt.start) < 86400000) break; 894 if (timeTmp > opt.start) timeTmp -= 86400000; 895 if (timeTmp < opt.start) timeTmp += 86400000; 896 } 897 if (!valid) return false; 898 } 899 } 900 return true; 901 } 902 903 904 function updateSelectableRange() 905 { 906 box.find('.day.invalid.tmp').removeClass('tmp invalid').addClass('valid'); 907 if (opt.start && !opt.end) 908 { 909 box.find('.day.toMonth.valid').each(function() 910 { 911 var time = parseInt($(this).attr('time'), 10); 912 if (!isValidTime(time)) 913 $(this).addClass('invalid tmp').removeClass('valid'); 914 else 915 $(this).addClass('valid tmp').removeClass('invalid'); 916 }); 917 } 918 919 return true; 920 } 921 922 923 function dayHovering(day) 924 { 925 var hoverTime = parseInt(day.attr('time')); 926 var tooltip = ''; 927 928 if (day.hasClass('has-tooltip') && day.attr('data-tooltip')) 929 { 930 tooltip = '<span style="white-space:nowrap">'+day.attr('data-tooltip')+'</span>'; 931 } 932 else if (!day.hasClass('invalid')) 933 { 934 if (opt.singleDate) 935 { 936 box.find('.day.hovering').removeClass('hovering'); 937 day.addClass('hovering'); 938 } 939 else 940 { 941 box.find('.day').each(function() 942 { 943 var time = parseInt($(this).attr('time')), 944 start = opt.start, 945 end = opt.end; 946 947 if ( time == hoverTime ) 948 { 949 $(this).addClass('hovering'); 950 } 951 else 952 { 953 $(this).removeClass('hovering'); 954 } 955 956 if ( 957 ( opt.start && !opt.end ) && 958 ( 959 ( opt.start < time && hoverTime >= time ) || 960 ( opt.start > time && hoverTime <= time ) 961 ) 962 ) 963 { 964 $(this).addClass('hovering'); 965 } 966 else 967 { 968 $(this).removeClass('hovering'); 969 } 970 }); 971 972 if (opt.start && !opt.end) 973 { 974 var days = countDays(hoverTime, opt.start); 975 if (opt.hoveringTooltip) 976 { 977 if (typeof opt.hoveringTooltip == 'function') 978 { 979 tooltip = opt.hoveringTooltip(days, opt.start, hoverTime); 980 } 981 else if (opt.hoveringTooltip === true && days > 1) 982 { 983 tooltip = days + ' ' + lang('days'); 984 } 985 } 986 } 987 } 988 } 989 990 if (tooltip) 991 { 992 var posDay = day.offset(); 993 var posBox = box.offset(); 994 995 var _left = posDay.left - posBox.left; 996 var _top = posDay.top - posBox.top; 997 _left += day.width()/2; 998 999 1000 var $tip = box.find('.date-range-length-tip'); 1001 var w = $tip.css({'visibility':'hidden', 'display':'none'}).html(tooltip).width(); 1002 var h = $tip.height(); 1003 _left -= w/2; 1004 _top -= h; 1005 setTimeout(function() 1006 { 1007 $tip.css({left:_left, top:_top, display:'block','visibility':'visible'}); 1008 },10); 1009 } 1010 else 1011 { 1012 box.find('.date-range-length-tip').hide(); 1013 } 1014 } 1015 1016 function clearHovering() 1017 { 1018 box.find('.day.hovering').removeClass('hovering'); 1019 box.find('.date-range-length-tip').hide(); 1020 } 1021 1022 function autoclose () { 1023 if (opt.singleDate === true) { 1024 if (initiated && opt.start ) 1025 { 1026 if (opt.autoClose) closeDatePicker(); 1027 } 1028 } else { 1029 if (initiated && opt.start && opt.end) 1030 { 1031 if (opt.autoClose) closeDatePicker(); 1032 } 1033 } 1034 } 1035 1036 function checkSelectionValid() 1037 { 1038 var days = Math.ceil( (opt.end - opt.start) / 86400000 ) + 1; 1039 if (opt.singleDate) { // Validate if only start is there 1040 if (opt.start && !opt.end) 1041 box.find('.drp_top-bar').removeClass('error').addClass('normal'); 1042 else 1043 box.find('.drp_top-bar').removeClass('error').removeClass('normal'); 1044 } 1045 else if ( opt.maxDays && days > opt.maxDays) 1046 { 1047 opt.start = false; 1048 opt.end = false; 1049 box.find('.day').removeClass('checked'); 1050 box.find('.drp_top-bar').removeClass('normal').addClass('error').find('.error-top').html( lang('less-than').replace('%d',opt.maxDays) ); 1051 } 1052 else if ( opt.minDays && days < opt.minDays) 1053 { 1054 opt.start = false; 1055 opt.end = false; 1056 box.find('.day').removeClass('checked'); 1057 box.find('.drp_top-bar').removeClass('normal').addClass('error').find('.error-top').html( lang('more-than').replace('%d',opt.minDays) ); 1058 } 1059 else 1060 { 1061 if (opt.start || opt.end) 1062 box.find('.drp_top-bar').removeClass('error').addClass('normal'); 1063 else 1064 box.find('.drp_top-bar').removeClass('error').removeClass('normal'); 1065 } 1066 1067 if ( (opt.singleDate && opt.start && !opt.end) || (!opt.singleDate && opt.start && opt.end) ) 1068 { 1069 box.find('.apply-btn').removeClass('disabled'); 1070 } 1071 else 1072 { 1073 box.find('.apply-btn').addClass('disabled'); 1074 } 1075 1076 if (opt.batchMode) 1077 { 1078 if ( 1079 (opt.start && opt.startDate && compare_day(opt.start, opt.startDate) < 0) || 1080 (opt.end && opt.endDate && compare_day(opt.end, opt.endDate) > 0) 1081 ) { 1082 opt.start = false; 1083 opt.end = false; 1084 box.find('.day').removeClass('checked'); 1085 } 1086 } 1087 } 1088 1089 function showSelectedInfo(forceValid,silent) 1090 {
1091 box.find('.start-day').html('...'); 1092 box.find('.end-day').html('...'); 1093 box.find('.selected-days').hide(); 1094 if (opt.start) 1095 { 1096 box.find('.start-day').html(getDateString(new Date(parseInt(opt.start)))); 1097 } 1098 if (opt.end) 1099 { 1100 box.find('.end-day').html(getDateString(new Date(parseInt(opt.end)))); 1101 } 1102 var dateRange; 1103 if (opt.start && opt.singleDate) 1104 { 1105 box.find('.apply-btn').removeClass('disabled'); 1106 dateRange = getDateString(new Date(opt.start)); 1107 opt.setValue.call(selfDom, dateRange, getDateString(new Date(opt.start)), getDateString(new Date(opt.end))); 1108 1109 if (initiated && !silent) 1110 { 1111 $(self).trigger('datepicker-change', 1112 { 1113 'value': dateRange, 1114 'date1' : new Date(opt.start) 1115 }); 1116 } 1117 } 1118 else if (opt.start && opt.end) 1119 { 1120 box.find('.selected-days').show().find('.selected-days-num').html(countDays(opt.end, opt.start)); 1121 box.find('.apply-btn').removeClass('disabled'); 1122 dateRange = getDateString(new Date(opt.start))+ opt.separator +getDateString(new Date(opt.end)); 1123 opt.setValue.call(selfDom,dateRange, getDateString(new Date(opt.start)), getDateString(new Date(opt.end))); 1124 if (initiated && !silent) 1125 { 1126 $(self).trigger('datepicker-change', 1127 { 1128 'value': dateRange, 1129 'date1' : new Date(opt.start), 1130 'date2' : new Date(opt.end) 1131 }); 1132 } 1133 } 1134 else if (forceValid) 1135 { 1136 box.find('.apply-btn').removeClass('disabled'); 1137 } 1138 else 1139 { 1140 box.find('.apply-btn').addClass('disabled'); 1141 } 1142 } 1143 1144 function countDays(start,end) 1145 { 1146 return Math.abs( daysFrom1970(start) - daysFrom1970(end) ) + 1; 1147 } 1148 1149 function setDateRange(date1,date2,silent) 1150 { 1151 if (date1.getTime() > date2.getTime()) 1152 { 1153 var tmp = date2; 1154 date2 = date1; 1155 date1 = tmp; 1156 tmp = null; 1157 } 1158 var valid = true; 1159 if (opt.startDate && compare_day(date1,opt.startDate) < 0) valid = false; 1160 if (opt.endDate && compare_day(date2,opt.endDate) > 0) valid = false; 1161 if (!valid) 1162 { 1163 showMonth(opt.startDate,'month1'); 1164 showMonth(nextMonth(opt.startDate),'month2'); 1165 showGap(); 1166 return; 1167 } 1168 1169 opt.start = date1.getTime(); 1170 opt.end = date2.getTime(); 1171 1172 if (opt.time.enabled) 1173 { 1174 renderTime('time1', date1); 1175 renderTime('time2', date2); 1176 } 1177 1178 if (opt.stickyMonths || (compare_day(date1,date2) > 0 && compare_month(date1,date2) === 0)) 1179 { 1180 if (opt.lookBehind) { 1181 date1 = prevMonth(date2); 1182 } else { 1183 date2 = nextMonth(date1); 1184 } 1185 } 1186 1187 if(opt.stickyMonths && opt.endDate !== false && compare_month(date2,opt.endDate) > 0) { 1188 date1 = prevMonth(date1); 1189 date2 = prevMonth(date2); 1190 } 1191 1192 if (!opt.stickyMonths) { 1193 if (compare_month(date1,date2) === 0) 1194 { 1195 if (opt.lookBehind) { 1196 date1 = prevMonth(date2); 1197 } else { 1198 date2 = nextMonth(date1); 1199 } 1200 } 1201 } 1202 1203 showMonth(date1,'month1'); 1204 showMonth(date2,'month2'); 1205 showGap(); 1206 checkSelectionValid(); 1207 showSelectedInfo(false,silent); 1208 autoclose(); 1209 } 1210 1211 function setSingleDate(date1) 1212 { 1213 1214 var valid = true; 1215 if (opt.startDate && compare_day(date1,opt.startDate) < 0) valid = false; 1216 if (opt.endDate && compare_day(date1,opt.endDate) > 0) valid = false; 1217 if (!valid) 1218 { 1219 showMonth(opt.startDate,'month1'); 1220 return; 1221 } 1222 1223 opt.start = date1.getTime(); 1224 1225 1226 if (opt.time.enabled) { 1227 renderTime('time1', date1); 1228 1229 } 1230 showMonth(date1,'month1'); 1231 if (opt.singleMonth !== true) { 1232 var date2 = nextMonth(date1); 1233 showMonth(date2, 'month2'); 1234 } 1235 showGap(); 1236 showSelectedInfo(); 1237 autoclose(); 1238 } 1239 1240 function showSelectedDays() 1241 { 1242 if (!opt.start && !opt.end) return; 1243 box.find('.day').each(function() 1244 { 1245 var time = parseInt($(this).attr('time')), 1246 start = opt.start, 1247 end = opt.end; 1248 if (opt.time.enabled) { 1249 time = moment(time).startOf('day').valueOf(); 1250 start = moment(start || moment().valueOf()).startOf('day').valueOf(); 1251 end = moment(end || moment().valueOf()).startOf('day').valueOf(); 1252 } 1253 if ( 1254 (opt.start && opt.end && end >= time && start <= time ) || 1255 ( opt.start && !opt.end && moment(start).format('YYYY-MM-DD') == moment(time).format('YYYY-MM-DD') ) 1256 ) 1257 { 1258 $(this).addClass('checked'); 1259 } 1260 else 1261 { 1262 $(this).removeClass('checked'); 1263 } 1264 1265 //add first-date-selected class name to the first date selected 1266 if ( opt.start && moment(start).format('YYYY-MM-DD') == moment(time).format('YYYY-MM-DD') ) 1267 { 1268 $(this).addClass('first-date-selected'); 1269 } 1270 else 1271 { 1272 $(this).removeClass('first-date-selected'); 1273 } 1274 //add last-date-selected 1275 if ( opt.end && moment(end).format('YYYY-MM-DD') == moment(time).format('YYYY-MM-DD') ) 1276 { 1277 $(this).addClass('last-date-selected'); 1278 } 1279 else 1280 { 1281 $(this).removeClass('last-date-selected'); 1282 } 1283 }); 1284 1285 box.find('.week-number').each(function() 1286 { 1287 if ($(this).attr('data-start-time') == opt.startWeek) 1288 { 1289 $(this).addClass('week-number-selected'); 1290 } 1291 }); 1292 } 1293 1294 function showMonth(date,month) 1295 { 1296 date = moment(date).toDate(); 1297 var monthName = nameMonth(date.getMonth()); 1298 box.find('.'+month+' .month-name').html(monthName+' '+date.getFullYear()); 1299 box.find('.'+month+' tbody').html(createMonthHTML(date)); 1300 opt[month] = date; 1301 updateSelectableRange(); 1302 } 1303 1304 function showTime(date,name) 1305 {
1306 box.find('.' + name).append(getTimeHTML()); 1307 renderTime(name, date); 1308 } 1309 1310 function nameMonth(m) 1311 { 1312 return lang('month-name')[m]; 1313 } 1314 1315 function getDateString(d) 1316 { 1317 return moment(d).format(opt.format); 1318 } 1319 1320 function showGap() 1321 { 1322 showSelectedDays(); 1323 var m1 = parseInt(moment(opt.month1).format('YYYYMM')); 1324 var m2 = parseInt(moment(opt.month2).format('YYYYMM')); 1325 var p = Math.abs(m1 - m2); 1326 var shouldShow = (p > 1 && p !=89); 1327 if (shouldShow) 1328 { 1329 box.addClass('has-gap').removeClass('no-gap').find('.gap').css('visibility','visible'); 1330 } 1331 else 1332 { 1333 box.removeClass('has-gap').addClass('no-gap').find('.gap').css('visibility','hidden'); 1334 } 1335 var h1 = box.find('table.month1').height(); 1336 var h2 = box.find('table.month2').height(); 1337 box.find('.gap').height(Math.max(h1,h2)+10); 1338 } 1339 1340 function closeDatePicker() 1341 { 1342 if (opt.alwaysOpen) return; 1343 1344 var afterAnim = function() 1345 { 1346 $(self).data('date-picker-opened',false); 1347 $(self).trigger('datepicker-closed', {relatedTarget: box}); 1348 }; 1349 if (opt.customCloseAnimation) 1350 { 1351 opt.customCloseAnimation.call(box.get(0), afterAnim); 1352 } 1353 else 1354 { 1355 $(box).slideUp(opt.duration, afterAnim); 1356 } 1357 $(self).trigger('datepicker-close', {relatedTarget: box}); 1358 } 1359 1360 function redrawDatePicker() 1361 { 1362 showMonth(opt.month1, 'month1'); 1363 showMonth(opt.month2, 'month2'); 1364 } 1365 1366 function compare_month(m1,m2) 1367 { 1368 var p = parseInt(moment(m1).format('YYYYMM')) - parseInt(moment(m2).format('YYYYMM')); 1369 if (p > 0 ) return 1; 1370 if (p === 0) return 0; 1371 return -1; 1372 } 1373 1374 function compare_day(m1,m2) 1375 { 1376 var p = parseInt(moment(m1).format('YYYYMMDD')) - parseInt(moment(m2).format('YYYYMMDD')); 1377 if (p > 0 ) return 1; 1378 if (p === 0) return 0; 1379 return -1; 1380 } 1381 1382 function nextMonth(month) 1383 { 1384 return moment(month).add(1, 'months').toDate(); 1385 } 1386 1387 function prevMonth(month) 1388 { 1389 return moment(month).add(-1, 'months').toDate(); 1390 } 1391 1392 function getTimeHTML() 1393 { 1394 return '<div>' + 1395 '<span>'+lang('Time')+': <span class="hour-val">00</span>:<span class="minute-val">00</span></span>' + 1396 '</div>' + 1397 '<div class="hour">' + 1398 '<label>'+lang('Hour')+': <input type="range" class="hour-range" name="hour" min="0" max="23"></label>' + 1399 '</div>' + 1400 '<div class="minute">' + 1401 '<label>'+lang('Minute')+': <input type="range" class="minute-range" name="minute" min="0" max="59"></label>' + 1402 '</div>'; 1403 } 1404 1405 function createDom() 1406 { 1407 var html = '<div class="date-picker-wrapper'; 1408 if ( opt.extraClass ) html += ' '+opt.extraClass+' '; 1409 if ( opt.singleDate ) html += ' single-date '; 1410 if ( !opt.showShortcuts ) html += ' no-shortcuts '; 1411 if ( !opt.showTopbar ) html += ' no-topbar '; 1412 if ( opt.customTopBar) html += ' custom-topbar '; 1413 html += '">'; 1414 1415 if (opt.showTopbar) 1416 { 1417 html += '<div class="drp_top-bar">'; 1418 1419 if (opt.customTopBar) 1420 { 1421 if (typeof opt.customTopBar == 'function') opt.customTopBar = opt.customTopBar(); 1422 html += '<div class="custom-top">'+opt.customTopBar+'</div>'; 1423 } 1424 else 1425 { 1426 html += '<div class="normal-top">' + 1427 '<span style="color:#333">'+lang('selected')+' </span> <b class="start-day">...</b>'; 1428 if ( ! opt.singleDate ) { 1429 html += ' <span class="separator-day">'+opt.separator+'</span> <b class="end-day">...</b> <i class="selected-days">(<span class="selected-days-num">3</span> '+lang('days')+')</i>'; 1430 } 1431 html += '</div>'; 1432 html += '<div class="error-top">error</div>' + 1433 '<div class="default-top">default</div>'; 1434 } 1435 1436 html += '<input type="button" class="apply-btn disabled'+ getApplyBtnClass() +'" value="'+lang('apply')+'" />'; 1437 html += '</div>'; 1438 } 1439 1440 var _colspan = opt.showWeekNumbers ? 6 : 5; 1441 html += '<div class="month-wrapper">' + 1442 '<table class="month1" cellspacing="0" border="0" cellpadding="0"><thead><tr class="caption"><th style="width:27px;"><span class="prev"><</span></th><th colspan="'+_colspan+'" class="month-name"></th><th style="width:27px;">' + (opt.singleDate || !opt.stickyMonths ? '<span class="next">></span>': '') + '</th></tr><tr class="week-name">'+getWeekHead()+'</thead><tbody></tbody></table>'; 1443 1444 if ( hasMonth2() ) 1445 { 1446 html += '<div class="gap">'+getGapHTML()+'</div>' + 1447 '<table class="month2" cellspacing="0" border="0" cellpadding="0"><thead><tr class="caption"><th style="width:27px;">' + (!opt.stickyMonths ? '<span class="prev"><</span>': '') + '</th><th colspan="'+_colspan+'" class="month-name"></th><th style="width:27px;"><span class="next">></span></th></tr><tr class="week-name">'+getWeekHead()+'</thead><tbody></tbody></table>'; 1448 } 1449 //+'</div>' 1450 html += '<div style="clear:both;height:0;font-size:0;"></div>' + 1451 '<div class="time">' + 1452 '<div class="time1"></div>'; 1453 if ( ! opt.singleDate ) { 1454 html += '<div class="time2"></div>'; 1455 } 1456 html += '</div>' + 1457 '<div style="clear:both;height:0;font-size:0;"></div>' + 1458 '</div>'; 1459 1460 html += '<div class="footer">'; 1461 if (opt.showShortcuts) 1462 { 1463 html += '<div class="shortcuts"><b>'+lang('shortcuts')+'</b>'; 1464 1465 var data = opt.shortcuts; 1466 if (data) 1467 { var name; 1468 if (data['prev-days'] && data['prev-days'].length > 0) 1469 { 1470 html += ' <span class="prev-days">'+lang('past'); 1471 for(var i=0;i<data['prev-days'].length; i++) 1472 { 1473 name = data['prev-days'][i]; 1474 name += (data['prev-days'][i] > 1) ? lang('days') : lang('day'); 1475 html += ' <a href="javascript:;" shortcut="day,-'+data['prev-days'][i]+'">'+name+'</a>'; 1476 } 1477 html+='</span>'; 1478 } 1479 1480 if (data['next-days'] && data['next-days'].length > 0) 1481 { 1482 html += '
1482<span class="next-days">'+lang('following'); 1483 for(var i=0;i<data['next-days'].length; i++) 1484 { 1485 name = data['next-days'][i]; 1486 name += (data['next-days'][i] > 1) ? lang('days') : lang('day'); 1487 html += ' <a href="javascript:;" shortcut="day,'+data['next-days'][i]+'">'+name+'</a>'; 1488 } 1489 html+= '</span>'; 1490 } 1491 1492 if (data.prev && data.prev.length > 0) 1493 { 1494 html += ' <span class="prev-buttons">'+lang('previous'); 1495 for(var i=0;i<data.prev.length; i++) 1496 { 1497 name = lang('prev-'+data.prev[i]); 1498 html += ' <a href="javascript:;" shortcut="prev,'+data.prev[i]+'">'+name+'</a>'; 1499 } 1500 html+='</span>'; 1501 } 1502 1503 if (data.next && data.next.length > 0) 1504 { 1505 html += ' <span class="next-buttons">'+lang('next'); 1506 for(var i=0;i<data.next.length; i++) 1507 { 1508 name = lang('next-'+data.next[i]); 1509 html += ' <a href="javascript:;" shortcut="next,'+data.next[i]+'">'+name+'</a>'; 1510 } 1511 html+='</span>'; 1512 } 1513 } 1514 1515 if (opt.customShortcuts) 1516 { 1517 for(var i=0;i<opt.customShortcuts.length; i++) 1518 { 1519 var sh = opt.customShortcuts[i]; 1520 html+= ' <span class="custom-shortcut"><a href="javascript:;" shortcut="custom">'+sh.name+'</a></span>'; 1521 } 1522 } 1523 html += '</div>'; 1524 } 1525 1526 // Add Custom Values Dom 1527 if (opt.showCustomValues) 1528 { 1529 html += '<div class="customValues"><b>'+(opt.customValueLabel || lang('custom-values'))+'</b>'; 1530 1531 if (opt.customValues) 1532 { 1533 for(var i=0;i<opt.customValues.length;i++) 1534 { 1535 var val = opt.customValues[i]; 1536 html+= ' <span class="custom-value"><a href="javascript:;" custom="'+ val.value+'">'+val.name+'</a></span>'; 1537 } 1538 } 1539 } 1540 1541 html += '</div></div>'; 1542 1543 1544 return $(html); 1545 } 1546 1547 function getApplyBtnClass() 1548 { 1549 var klass = ''; 1550 if (opt.autoClose === true) { 1551 klass += ' hide'; 1552 } 1553 if (opt.applyBtnClass !== '') { 1554 klass += ' ' + opt.applyBtnClass; 1555 } 1556 return klass; 1557 } 1558 1559 function getWeekHead() 1560 { 1561 var prepend = opt.showWeekNumbers ? '<th>'+lang('week-number')+'</th>' : ''; 1562 if (opt.startOfWeek == 'monday') 1563 { 1564 return prepend+'<th>'+lang('week-1')+'</th>' + 1565 '<th>'+lang('week-2')+'</th>' + 1566 '<th>'+lang('week-3')+'</th>' + 1567 '<th>'+lang('week-4')+'</th>' + 1568 '<th>'+lang('week-5')+'</th>' + 1569 '<th>'+lang('week-6')+'</th>' + 1570 '<th>'+lang('week-7')+'</th>'; 1571 } 1572 else 1573 { 1574 return prepend+'<th>'+lang('week-7')+'</th>' + 1575 '<th>'+lang('week-1')+'</th>' + 1576 '<th>'+lang('week-2')+'</th>' + 1577 '<th>'+lang('week-3')+'</th>' + 1578 '<th>'+lang('week-4')+'</th>' + 1579 '<th>'+lang('week-5')+'</th>' + 1580 '<th>'+lang('week-6')+'</th>'; 1581 } 1582 } 1583 1584 function isMonthOutOfBounds(month) 1585 { 1586 month = moment(month); 1587 if (opt.startDate && month.endOf('month').isBefore(opt.startDate)) 1588 { 1589 return true; 1590 } 1591 if (opt.endDate && month.startOf('month').isAfter(opt.endDate)) 1592 { 1593 return true; 1594 } 1595 return false; 1596 } 1597 1598 function getGapHTML() 1599 { 1600 var html = ['<div class="gap-top-mask"></div><div class="gap-bottom-mask"></div><div class="gap-lines">']; 1601 for(var i=0;i<20;i++) 1602 { 1603 html.push('<div class="gap-line">' + 1604 '<div class="gap-1"></div>' + 1605 '<div class="gap-2"></div>' + 1606 '<div class="gap-3"></div>' + 1607 '</div>'); 1608 } 1609 html.push('</div>'); 1610 return html.join(''); 1611 } 1612 1613 function hasMonth2() 1614 { 1615 return (!opt.singleMonth); 1616 } 1617 1618 function attributesCallbacks(initialObject,callbacksArray,today) 1619 { 1620 var resultObject = $.extend(true, {}, initialObject); 1621 1622 $.each(callbacksArray, function(cbAttrIndex, cbAttr){ 1623 var addAttributes = cbAttr(today); 1624 for(var attr in addAttributes){ 1625 if(resultObject.hasOwnProperty(attr)){ 1626 resultObject[attr] += addAttributes[attr]; 1627 }else{ 1628 resultObject[attr] = addAttributes[attr]; 1629 } 1630 } 1631 }); 1632 1633 var attrString = ''; 1634 1635 for(var attr in resultObject){ 1636 if(resultObject.hasOwnProperty(attr)){ 1637 attrString += attr + '="' + resultObject[attr] + '" '; 1638 } 1639 } 1640 1641 return attrString; 1642 } 1643 1644 function daysFrom1970(t) 1645 { 1646 return Math.floor(toLocalTimestamp(t) / 86400000); 1647 } 1648 1649 function toLocalTimestamp(t) 1650 { 1651 if (moment.isMoment(t)) t = t.toDate().getTime(); 1652 if (typeof t == 'object' && t.getTime) t = t.getTime(); 1653 if (typeof t == 'string' && !t.match(/\d{13}/)) t = moment(t,opt.format).toDate().getTime(); 1654 t = parseInt(t, 10) - new Date().getTimezoneOffset()*60*1000; 1655 return t; 1656 } 1657 1658 function createMonthHTML(d) 1659 { 1660 var days = []; 1661 d.setDate(1); 1662 var lastMonth = new Date(d.getTime() - 86400000); 1663 var now = new Date(); 1664 1665 var dayOfWeek = d.getDay(); 1666 if((dayOfWeek === 0) && (opt.startOfWeek === 'monday')) { 1667 // add one week 1668 dayOfWeek = 7; 1669 } 1670 var today,valid; 1671 1672 if (dayOfWeek > 0) 1673 { 1674 for (var i = dayOfWeek; i > 0; i--) 1675 { 1676 var day = new Date(d.getTime() - 86400000*i); 1677 valid = isValidTime(day.getTime()); 1678 if (opt.startDate && compare_day(day,opt.startDate) < 0) valid = false;
1679 if (opt.endDate && compare_day(day,opt.endDate) > 0) valid = false; 1680 days.push( 1681 { 1682 date: day, 1683 type:'lastMonth', 1684 day: day.getDate(), 1685 time:day.getTime(), 1686 valid:valid 1687 }); 1688 } 1689 } 1690 var toMonth = d.getMonth(); 1691 for(var i=0; i<40; i++) 1692 { 1693 today = moment(d).add(i, 'days').toDate(); 1694 valid = isValidTime(today.getTime()); 1695 if (opt.startDate && compare_day(today,opt.startDate) < 0) valid = false; 1696 if (opt.endDate && compare_day(today,opt.endDate) > 0) valid = false; 1697 days.push( 1698 { 1699 date: today, 1700 type: today.getMonth() == toMonth ? 'toMonth' : 'nextMonth', 1701 day: today.getDate(), 1702 time:today.getTime(), 1703 valid:valid 1704 }); 1705 } 1706 var html = []; 1707 for(var week=0; week<6; week++) 1708 { 1709 if (days[week*7].type == 'nextMonth') break; 1710 html.push('<tr>'); 1711 1712 for(var day = 0; day<7; day++) 1713 { 1714 var _day = (opt.startOfWeek == 'monday') ? day+1 : day; 1715 today = days[week*7+_day]; 1716 var highlightToday = moment(today.time).format('L') == moment(now).format('L'); 1717 today.extraClass = ''; 1718 today.tooltip = ''; 1719 if(today.valid && opt.beforeShowDay && typeof opt.beforeShowDay == 'function') 1720 { 1721 var _r = opt.beforeShowDay(moment(today.time).toDate()); 1722 today.valid = _r[0]; 1723 today.extraClass = _r[1] || ''; 1724 today.tooltip = _r[2] || ''; 1725 if (today.tooltip !== '') today.extraClass += ' has-tooltip '; 1726 } 1727 1728 var todayDivAttr = { 1729 time: today.time, 1730 'data-tooltip': today.tooltip, 1731 'class': 'day '+today.type+' '+today.extraClass+' '+(today.valid ? 'valid' : 'invalid')+' '+(highlightToday?'real-today':'') 1732 }; 1733 1734 if (day === 0 && opt.showWeekNumbers) 1735 { 1736 html.push('<td><div class="week-number" data-start-time="'+today.time+'">'+opt.getWeekNumber(today.date)+'</div></td>'); 1737 } 1738 1739 html.push('<td ' + attributesCallbacks({},opt.dayTdAttrs,today) + '><div ' + attributesCallbacks(todayDivAttr,opt.dayDivAttrs,today) + '>'+showDayHTML(today.time, today.day)+'</div></td>'); 1740 } 1741 html.push('</tr>'); 1742 } 1743 return html.join(''); 1744 } 1745 1746 function showDayHTML(time, date) 1747 { 1748 if (opt.showDateFilter && typeof opt.showDateFilter == 'function') return opt.showDateFilter(time, date); 1749 return date; 1750 } 1751 1752 function getLanguages() 1753 { 1754 if (opt.language == 'auto') 1755 { 1756 var language = navigator.language ? navigator.language : navigator.browserLanguage; 1757 if (!language) return $.dateRangePickerLanguages['default']; 1758 language = language.toLowerCase(); 1759 for(var key in $.dateRangePickerLanguages) 1760 { 1761 if (language.indexOf(key) !== -1) 1762 { 1763 return $.dateRangePickerLanguages[key]; 1764 } 1765 } 1766 return $.dateRangePickerLanguages['default']; 1767 } 1768 else if ( opt.language && opt.language in $.dateRangePickerLanguages) 1769 { 1770 return $.dateRangePickerLanguages[opt.language]; 1771 } 1772 else 1773 { 1774 return $.dateRangePickerLanguages['default']; 1775 } 1776 } 1777 1778 /** 1779 * translate language string 1780 */ 1781 function lang(t) 1782 { 1783 var _t = t.toLowerCase(); 1784 var re = (t in langs) ? langs[t] : ( _t in langs) ? langs[_t] : null; 1785 var defaultLanguage = $.dateRangePickerLanguages['default']; 1786 if (re == null) re = (t in defaultLanguage) ? defaultLanguage[t] : ( _t in defaultLanguage) ? defaultLanguage[_t] : ''; 1787 return re; 1788 } 1789 1790 function getDefaultTime() 1791 { 1792 var defaultTime = opt.defaultTime ? opt.defaultTime : new Date(); 1793 1794 if (opt.lookBehind) 1795 { 1796 if (opt.startDate && compare_month(defaultTime, opt.startDate) < 0 ) defaultTime = nextMonth(moment(opt.startDate).toDate()); 1797 if (opt.endDate && compare_month(defaultTime,opt.endDate) > 0 ) defaultTime = moment(opt.endDate).toDate(); 1798 } 1799 else 1800 { 1801 if (opt.startDate && compare_month(defaultTime,opt.startDate) < 0 ) defaultTime = moment(opt.startDate).toDate(); 1802 if (opt.endDate && compare_month(nextMonth(defaultTime),opt.endDate) >
1802 0 ) defaultTime = prevMonth(moment(opt.endDate).toDate()); 1803 } 1804 1805 if (opt.singleDate) 1806 { 1807 if (opt.startDate && compare_month(defaultTime,opt.startDate) < 0 ) defaultTime = moment(opt.startDate).toDate(); 1808 if (opt.endDate && compare_month(defaultTime,opt.endDate) > 0 ) defaultTime = moment(opt.endDate).toDate(); 1809 } 1810 1811 return defaultTime; 1812 } 1813 1814 function resetMonthsView(time) 1815 { 1816 if (!time) { 1817 time = getDefaultTime(); 1818 } 1819 1820 if (opt.lookBehind) 1821 { 1822 showMonth(prevMonth(time),'month1'); 1823 showMonth(time,'month2'); 1824 } 1825 else 1826 { 1827 showMonth(time,'month1'); 1828 showMonth(nextMonth(time),'month2'); 1829 } 1830 1831 if (opt.singleDate) 1832 { 1833 showMonth(time,'month1'); 1834 } 1835 1836 showSelectedDays(); 1837 showGap(); 1838 } 1839 1840 }; 1841}));
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.