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