vendor: 15,720 bytes, lines 1-382
1/** 2* @version: 3.1 3* @author: Dan Grossman http://www.dangrossman.info/ 4* @copyright: Copyright (c) 2012-2019 Dan Grossman. All rights reserved. 5* @license: Licensed under the MIT license. See http://www.opensource.org/licenses/mit-license.php 6* @website: http://www.daterangepicker.com/ 7*/ 8// Following the UMD template https://github.com/umdjs/umd/blob/master/templates/returnExportsGlobal.js 9(function (root, factory) { 10 if (typeof define === 'function' && define.amd) { 11 // AMD. Make globaly available as well 12 define(['moment', 'jquery'], function (moment, jquery) { 13 if (!jquery.fn) jquery.fn = {}; // webpack server rendering 14 if (typeof moment !== 'function' && moment.hasOwnProperty('default')) moment = moment['default'] 15 return factory(moment, jquery); 16 }); 17 } else if (typeof module === 'object' && module.exports) { 18 // Node / Browserify 19 //isomorphic issue 20 var jQuery = (typeof window != 'undefined') ? window.jQuery : undefined; 21 if (!jQuery) { 22 jQuery = require('jquery'); 23 if (!jQuery.fn) jQuery.fn = {}; 24 } 25 var moment = (typeof window != 'undefined' && typeof window.moment != 'undefined') ? window.moment : require('moment'); 26 module.exports = factory(moment, jQuery); 27 } else { 28 // Browser globals 29 root.daterangepicker = factory(root.moment, root.jQuery); 30 } 31}(this, function(moment, $) { 32 var DateRangePicker = function(element, options, cb) { 33 34 //default settings for options 35 this.parentEl = 'body'; 36 this.element = $(element); 37 this.startDate = moment().startOf('day'); 38 this.endDate = moment().endOf('day'); 39 this.minDate = false; 40 this.maxDate = false; 41 this.maxSpan = false; 42 this.autoApply = false; 43 this.singleDatePicker = false; 44 this.showDropdowns = false; 45 this.minYear = moment().subtract(100, 'year').format('YYYY'); 46 this.maxYear = moment().add(100, 'year').format('YYYY'); 47 this.showWeekNumbers = false; 48 this.showISOWeekNumbers = false; 49 this.showCustomRangeLabel = true; 50 this.timePicker = false; 51 this.timePicker24Hour = false; 52 this.timePickerIncrement = 1; 53 this.timePickerSeconds = false; 54 this.linkedCalendars = true; 55 this.autoUpdateInput = true; 56 this.alwaysShowCalendars = false; 57 this.ranges = {}; 58 this.dateRangeSelected = false; 59 this.leftLabel = 'NUO'; 60 this.rightLabel = 'IKI'; 61 62 this.opens = 'right'; 63 if (this.element.hasClass('pull-right')) 64 this.opens = 'left'; 65 66 this.drops = 'down'; 67 if (this.element.hasClass('dropup')) 68 this.drops = 'up'; 69 70 this.buttonClasses = 'btn btn-sm'; 71 this.applyButtonClasses = 'btn-primary'; 72 this.cancelButtonClasses = 'btn-default'; 73 74 this.locale = { 75 direction: 'ltr', 76 format: moment.localeData().longDateFormat('L'), 77 separator: ' - ', 78 applyLabel: 'Apply', 79 cancelLabel: 'Cancel', 80 weekLabel: 'W', 81 customRangeLabel: 'Custom Range', 82 daysOfWeek: moment.weekdaysMin(), 83 monthNames: moment.monthsShort(), 84 firstDay: moment.localeData().firstDayOfWeek() 85 }; 86 87 this.callback = function() { }; 88 89 //some state information 90 this.isShowing = false; 91 this.leftCalendar = {}; 92 this.rightCalendar = {}; 93 94 //custom options from user 95 if (typeof options !== 'object' || options === null) 96 options = {}; 97 98 //allow setting options with data attributes 99 //data-api options will be overwritten with custom javascript options 100 options = $.extend(this.element.data(), options); 101 102 //html template for the picker UI 103 if (typeof options.template !== 'string' && !(options.template instanceof $)) 104 options.template = 105 '<div class="daterangepicker">' + 106 '<div class="ranges"></div>' + 107 '<div class="drp-calendar-tabs hide-in-desktop-and-tablet">'+ 108 '<div class="drp-calendar-tab-left drp-calendar-tab active" data-orientation="left">' + this.leftLabel + '</div>'+ 109 '<div class="drp-calendar-tab-right drp-calendar-tab" data-orientation="right">' + this.rightLabel + '</div>'+ 110 '</div>'+ 111 '<div class="drp-calendar left">' + '<div class="drp-calendar-label hide-in-mobile">' + this.leftLabel + '</div>' + 112 '<div class="calendar-table"></div>' + 113 '<div class="calendar-time"></div>' + 114 '</div>' + 115 '<div class="drp-calendar right">' + '<div class="drp-calendar-label hide-in-mobile">' + this.rightLabel + '</div>' + 116 '<div class="calendar-table"></div>' + 117 '<div class="calendar-time"></div>' + 118 '</div>' + 119 '<div class="drp-buttons">' + 120 '<span class="drp-selected"></span>' + 121 '<button class="cancelBtn" type="button"></button>' + 122 '<button class="applyBtn" disabled="disabled" type="button"></button> ' + 123 '</div>' + 124 '</div>'; 125 126 this.parentEl = (options.parentEl && $(options.parentEl).length) ? $(options.parentEl) : $(this.parentEl); 127 this.container = $(options.template).appendTo(this.parentEl); 128 129 // 130 // handle all the possible options overriding defaults 131 // 132 133 if (typeof options.locale === 'object') { 134 135 if (typeof options.locale.direction === 'string') 136 this.locale.direction = options.locale.direction; 137 138 if (typeof options.locale.format === 'string') 139 this.locale.format = options.locale.format; 140 141 if (typeof options.locale.separator === 'string') 142 this.locale.separator = options.locale.separator; 143 144 if (typeof options.locale.daysOfWeek === 'object') 145 this.locale.daysOfWeek = options.locale.daysOfWeek.slice(); 146 147 if (typeof options.locale.monthNames === 'object') 148 this.locale.monthNames = options.locale.monthNames.slice(); 149 150 if (typeof options.locale.firstDay === 'number') 151 this.locale.firstDay = options.locale.firstDay; 152 153 if (typeof options.locale.applyLabel === 'string') 154 this.locale.applyLabel = options.locale.applyLabel; 155 156 if (typeof options.locale.cancelLabel === 'string') 157 this.locale.cancelLabel = options.locale.cancelLabel; 158 159 if (typeof options.locale.weekLabel === 'string') 160 this.locale.weekLabel = options.locale.weekLabel; 161 162 if (typeof options.locale.customRangeLabel === 'string'){ 163 //Support unicode chars in the custom range name. 164 var elem = document.createElement('textarea'); 165 elem.innerHTML = options.locale.customRangeLabel; 166 var rangeHtml = elem.value; 167 this.locale.customRangeLabel = rangeHtml; 168 } 169 } 170 this.container.addClass(this.locale.direction); 171 172 if (typeof options.startDate === 'string') 173 this.startDate = moment(options.startDate, this.locale.format); 174 175 if (typeof options.endDate === 'string') 176 this.endDate = moment(options.endDate, this.locale.format); 177 178 if (typeof options.minDate === 'string') 179 this.minDate = moment(options.minDate, this.locale.format); 180 181 if (typeof options.maxDate === 'string') 182 this.maxDate = moment(options.maxDate, this.locale.format); 183 184 if (typeof options.startDate === 'object') 185 this.startDate = moment(options.startDate); 186 187 if (typeof options.endDate === 'object') 188 this.endDate = moment(options.endDate); 189 190 if (typeof options.minDate === 'object') 191 this.minDate = moment(options.minDate); 192 193 if (typeof options.maxDate === 'object') 194 this.maxDate = moment(options.maxDate); 195 196 // sanity check for bad options 197 if (this.minDate && this.startDate.isBefore(this.minDate)) 198 this.startDate = this.minDate.clone(); 199 200 // sanity check for bad options 201 if (this.maxDate && this.endDate.isAfter(this.maxDate)) 202 this.endDate = this.maxDate.clone(); 203 204 if (typeof options.applyButtonClasses === 'string') 205 this.applyButtonClasses = options.applyButtonClasses; 206 207 if (typeof options.applyClass === 'string') //backwards compat 208 this.applyButtonClasses = options.applyClass; 209 210 if (typeof options.cancelButtonClasses === 'string') 211 this.cancelButtonClasses = options.cancelButtonClasses; 212 213 if (typeof options.cancelClass === 'string') //backwards compat 214 this.cancelButtonClasses = options.cancelClass; 215 216 if (typeof options.maxSpan === 'object') 217 this.maxSpan = options.maxSpan; 218 219 if (typeof options.dateLimit === 'object') //backwards compat 220 this.maxSpan = options.dateLimit; 221 222 if (typeof options.opens === 'string') 223 this.opens = options.opens; 224 225 if (typeof options.drops === 'string') 226 this.drops = options.drops; 227 228 if (typeof options.showWeekNumbers === 'boolean') 229 this.showWeekNumbers = options.showWeekNumbers; 230 231 if (typeof options.showISOWeekNumbers === 'boolean') 232 this.showISOWeekNumbers = options.showISOWeekNumbers; 233 234 if (typeof options.buttonClasses === 'string') 235 this.buttonClasses = options.buttonClasses; 236 237 if (typeof options.buttonClasses === 'object') 238 this.buttonClasses = options.buttonClasses.join(' '); 239 240 if (typeof options.showDropdowns === 'boolean') 241 this.showDropdowns = options.showDropdowns; 242 243 if (typeof options.minYear === 'number') 244 this.minYear = options.minYear; 245 246 if (typeof options.maxYear === 'number') 247 this.maxYear = options.maxYear; 248 249 if (typeof options.showCustomRangeLabel === 'boolean') 250 this.showCustomRangeLabel = options.showCustomRangeLabel; 251 252 if (typeof options.singleDatePicker === 'boolean') { 253 this.singleDatePicker = options.singleDatePicker; 254 if (this.singleDatePicker) 255 this.endDate = this.startDate.clone(); 256 } 257 258 if (typeof options.timePicker === 'boolean') 259 this.timePicker = options.timePicker; 260 261 if (typeof options.timePickerSeconds === 'boolean') 262 this.timePickerSeconds = options.timePickerSeconds; 263 264 if (typeof options.timePickerIncrement === 'number') 265 this.timePickerIncrement = options.timePickerIncrement; 266 267 if (typeof options.timePicker24Hour === 'boolean') 268 this.timePicker24Hour = options.timePicker24Hour; 269 270 if (typeof options.autoApply === 'boolean') 271 this.autoApply = options.autoApply; 272 273 if (typeof options.autoUpdateInput === 'boolean') 274 this.autoUpdateInput = options.autoUpdateInput; 275 276 if (typeof options.linkedCalendars === 'boolean') 277 this.linkedCalendars = options.linkedCalendars; 278 279 if (typeof options.isInvalidDate === 'function') 280 this.isInvalidDate = options.isInvalidDate; 281 282 if (typeof options.isCustomDate === 'function') 283 this.isCustomDate = options.isCustomDate; 284 285 if (typeof options.alwaysShowCalendars === 'boolean') 286 this.alwaysShowCalendars = options.alwaysShowCalendars; 287 288 // update day names order to firstDay 289 if (this.locale.firstDay != 0) { 290 var iterator = this.locale.firstDay; 291 while (iterator > 0) { 292 this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift()); 293 iterator--; 294 } 295 } 296 297 var start, end, range; 298 299 //if no start/end dates set, check if an input element contains initial values 300 if (typeof options.startDate === 'undefined' && typeof options.endDate === 'undefined') { 301 if ($(this.element).is(':text')) { 302 var val = $(this.element).val(), 303 split = val.split(this.locale.separator); 304 305 start = end = null; 306 307 if (split.length == 2) { 308 start = moment(split[0], this.locale.format); 309 end = moment(split[1], this.locale.format); 310 } else if (this.singleDatePicker && val !== "") { 311 start = moment(val, this.locale.format); 312 end = moment(val, this.locale.format); 313 } 314 if (start !== null && end !== null) { 315 this.setStartDate(start); 316 this.setEndDate(end); 317 } 318 } 319 } 320 321 if (typeof options.ranges === 'object') { 322 for (range in options.ranges) { 323 324 if (typeof options.ranges[range][0] === 'string') 325 start = moment(options.ranges[range][0], this.locale.format); 326 else 327 start = moment(options.ranges[range][0]); 328 329 if (typeof options.ranges[range][1] === 'string') 330 end = moment(options.ranges[range][1], this.locale.format); 331 else 332 end = moment(options.ranges[range][1]); 333 334 // If the start or end date exceed those allowed by the minDate or maxSpan 335 // options, shorten the range to the allowable period. 336 if (this.minDate && start.isBefore(this.minDate)) 337 start = this.minDate.clone(); 338 339 var maxDate = this.maxDate; 340 if (this.maxSpan && maxDate && start.clone().add(this.maxSpan).isAfter(maxDate)) 341 maxDate = start.clone().add(this.maxSpan); 342 if (maxDate && end.isAfter(maxDate)) 343 end = maxDate.clone(); 344 345 // If the end of the range is before the minimum or the start of the range is 346 // after the maximum, don't display this range option at all. 347 if ((this.minDate && end.isBefore(this.minDate, this.timepicker ? 'minute' : 'day')) 348 || (maxDate && start.isAfter(maxDate, this.timepicker ? 'minute' : 'day'))) 349 continue; 350 351 //Support unicode chars in the range names. 352 var elem = document.createElement('textarea'); 353 elem.innerHTML = range; 354 var rangeHtml = elem.value; 355 356 this.ranges[rangeHtml] = [start, end]; 357 } 358 359 var list = '<ul>'; 360 for (range in this.ranges) { 361 list += '<li data-range-key="' + range + '">' + range + '</li>'; 362 } 363 if (this.showCustomRangeLabel) { 364 list += '<li data-range-key="' + this.locale.customRangeLabel + '">' + this.locale.customRangeLabel + '</li>'; 365 } 366 list += '</ul>'; 367 this.container.find('.ranges').prepend(list); 368 } 369 370 if (typeof cb === 'function') { 371 this.callback = cb; 372 } 373 374 if (!this.timePicker) { 375 this.startDate = this.startDate.startOf('day'); 376 this.endDate = this.endDate.endOf('day'); 377 this.container.find('.calendar-time').hide(); 378 } 379 380 //can't be used together for now 381 if (this.timePicker && this.autoApply) 382 this.autoApply = false;
383 384 if (this.autoApply) { 385 this.container.addClass('auto-apply'); 386 } 387 388 if (typeof options.ranges === 'object') 389 this.container.addClass('show-ranges'); 390 391 if (this.singleDatePicker) { 392 this.container.addClass('single'); 393 this.container.find('.drp-calendar.left').addClass('single'); 394 this.container.find('.drp-calendar.left').show(); 395 this.container.find('.drp-calendar.right').hide(); 396 if (!this.timePicker && this.autoApply) { 397 this.container.addClass('auto-apply'); 398 } 399 } 400 401 if ((typeof options.ranges === 'undefined' && !this.singleDatePicker) || this.alwaysShowCalendars) { 402 this.container.addClass('show-calendar'); 403 } 404 405 this.container.addClass('opens' + this.opens); 406 407 //apply CSS classes and labels to buttons 408 this.container.find('.applyBtn, .cancelBtn').addClass(this.buttonClasses); 409 if (this.applyButtonClasses.length) 410 this.container.find('.applyBtn').addClass(this.applyButtonClasses); 411 if (this.cancelButtonClasses.length) 412 this.container.find('.cancelBtn').addClass(this.cancelButtonClasses); 413 this.container.find('.applyBtn').html(this.locale.applyLabel); 414 this.container.find('.cancelBtn').html(this.locale.cancelLabel); 415 416 // 417 // event listeners 418 // 419 420 this.container.find('.drp-calendar') 421 .on('click.daterangepicker', '.prev', $.proxy(this.clickPrev, this)) 422 .on('click.daterangepicker', '.next', $.proxy(this.clickNext, this)) 423 .on('mousedown.daterangepicker', 'td.available', $.proxy(this.clickDate, this)) 424 .on('mouseenter.daterangepicker', 'td.available', $.proxy(this.hoverDate, this)) 425 .on('change.daterangepicker', 'select.yearselect', $.proxy(this.monthOrYearChanged, this)) 426 .on('change.daterangepicker', 'select.monthselect', $.proxy(this.monthOrYearChanged, this)) 427 .on('change.daterangepicker', 'select.hourselect,select.minuteselect,select.secondselect,select.ampmselect', $.proxy(this.timeChanged, this)); 428 429 this.container.find('.ranges') 430 .on('click.daterangepicker', 'li', $.proxy(this.clickRange, this)); 431 432 this.container.find('.drp-calendar-tab') 433 .on( 'click', function(e){ 434 var orientation = $(this).data('orientation'); 435 $('.drp-calendar-tab').removeClass('active') 436 437 if (orientation == 'left'){ 438 $('.drp-calendar-tab-left').addClass('active'); 439 $('.drp-calendar.left').show(); 440 $('.drp-calendar.right').hide(); 441 } else { 442 $('.drp-calendar-tab-right').addClass('active'); 443 $('.drp-calendar.right').show(); 444 $('.drp-calendar.left').hide(); 445 446 } 447 }) 448 449 this.container.find('.drp-buttons') 450 .on('click.daterangepicker', 'button.applyBtn', $.proxy(this.clickApply, this)) 451 .on('click.daterangepicker', 'button.cancelBtn', $.proxy(this.clickCancel, this)); 452 453 if (this.element.is('input') || this.element.is('button')) { 454 this.element.on('click.daterangepicker', $.proxy(this.toggle, this)); 455 this.element.on('keydown.daterangepicker', $.proxy(this.toggle, this)); 456/* this.element.on({ 457 'click.daterangepicker': $.proxy(this.show, this), 458 'focus.daterangepicker': $.proxy(this.show, this), 459 'keyup.daterangepicker': $.proxy(this.elementChanged, this), 460 'keydown.daterangepicker': $.proxy(this.keydown, this) //IE 11 compatibility 461 });*/ 462 } else { 463 this.element.on('click.daterangepicker', $.proxy(this.toggle, this)); 464 this.element.on('keydown.daterangepicker', $.proxy(this.toggle, this)); 465 } 466 467 // 468 // if attached to a text input, set the initial value 469 // 470 471 this.updateElement(); 472 473 }; 474 475 DateRangePicker.prototype = { 476 477 constructor: DateRangePicker, 478 479 setStartDate: function(startDate) { 480 if (typeof startDate === 'string') 481 this.startDate = moment(startDate, this.locale.format); 482 483 if (typeof startDate === 'object') 484 this.startDate = moment(startDate); 485 486 if (!this.timePicker) 487 this.startDate = this.startDate.startOf('day'); 488 489 if (this.timePicker && this.timePickerIncrement) 490 this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); 491 492 if (this.minDate && this.startDate.isBefore(this.minDate)) { 493 this.startDate = this.minDate.clone(); 494 if (this.timePicker && this.timePickerIncrement) 495 this.startDate.minute(Math.round(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); 496 } 497 498 if (this.maxDate && this.startDate.isAfter(this.maxDate)) { 499 this.startDate = this.maxDate.clone(); 500 if (this.timePicker && this.timePickerIncrement) 501 this.startDate.minute(Math.floor(this.startDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); 502 } 503 504 if (!this.isShowing) 505 this.updateElement(); 506 507 this.updateMonthsInView(); 508 }, 509
vendor: 28,911 bytes, lines 510-1161
510 setEndDate: function(endDate) { 511 if (typeof endDate === 'string') 512 this.endDate = moment(endDate, this.locale.format); 513 514 if (typeof endDate === 'object') 515 this.endDate = moment(endDate); 516 517 if (!this.timePicker) 518 this.endDate = this.endDate.endOf('day'); 519 520 if (this.timePicker && this.timePickerIncrement) 521 this.endDate.minute(Math.round(this.endDate.minute() / this.timePickerIncrement) * this.timePickerIncrement); 522 523 if (this.endDate.isBefore(this.startDate)) 524 this.endDate = this.startDate.clone(); 525 526 if (this.maxDate && this.endDate.isAfter(this.maxDate)) 527 this.endDate = this.maxDate.clone(); 528 529 if (this.maxSpan && this.startDate.clone().add(this.maxSpan).isBefore(this.endDate)) 530 this.endDate = this.startDate.clone().add(this.maxSpan); 531 532 this.previousRightTime = this.endDate.clone(); 533 534 this.container.find('.drp-selected').html(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); 535 536 if (!this.isShowing) 537 this.updateElement(); 538 539 this.updateMonthsInView(); 540 }, 541 542 isInvalidDate: function() { 543 return false; 544 }, 545 546 isCustomDate: function() { 547 return false; 548 }, 549 550 updateView: function() { 551 if (this.timePicker) { 552 this.renderTimePicker('left'); 553 this.renderTimePicker('right'); 554 if (!this.endDate) { 555 this.container.find('.right .calendar-time select').prop('disabled', true).addClass('disabled'); 556 } else { 557 this.container.find('.right .calendar-time select').prop('disabled', false).removeClass('disabled'); 558 } 559 } 560 if (this.endDate) 561 this.container.find('.drp-selected').html(this.startDate.format(this.locale.format) + this.locale.separator + this.endDate.format(this.locale.format)); 562 563 564 this.updateMonthsInView(); 565 this.updateCalendars(); 566 this.updateFormInputs(); 567 }, 568 569 updateMonthsInView: function() { 570 if (this.endDate) { 571 572 //if both dates are visible already, do nothing 573 if (!this.singleDatePicker && this.leftCalendar.month && this.rightCalendar.month && 574 (this.startDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.startDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM')) 575 && 576 (this.endDate.format('YYYY-MM') == this.leftCalendar.month.format('YYYY-MM') || this.endDate.format('YYYY-MM') == this.rightCalendar.month.format('YYYY-MM')) 577 ) { 578 return; 579 } 580 581 this.leftCalendar.month = this.startDate.clone().date(2); 582 if (!this.linkedCalendars && (this.endDate.month() != this.startDate.month() || this.endDate.year() != this.startDate.year())) { 583 this.rightCalendar.month = this.endDate.clone().date(2); 584 } else { 585 this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month'); 586 } 587 588 589 } else { 590 if (this.leftCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM') && this.rightCalendar.month.format('YYYY-MM') != this.startDate.format('YYYY-MM')) { 591 this.leftCalendar.month = this.startDate.clone().date(2); 592 this.rightCalendar.month = this.startDate.clone().date(2).add(1, 'month'); 593 } 594 } 595 if (this.maxDate && this.linkedCalendars && !this.singleDatePicker && this.rightCalendar.month > this.maxDate) { 596 this.rightCalendar.month = this.maxDate.clone().date(2); 597 this.leftCalendar.month = this.maxDate.clone().date(2).subtract(1, 'month'); 598 } 599 600 }, 601 602 updateCalendars: function() { 603 604 if (this.timePicker) { 605 var hour, minute, second; 606 if (this.endDate) { 607 hour = parseInt(this.container.find('.left .hourselect').val(), 10); 608 minute = parseInt(this.container.find('.left .minuteselect').val(), 10); 609 if (isNaN(minute)) { 610 minute = parseInt(this.container.find('.left .minuteselect option:last').val(), 10); 611 } 612 second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; 613 if (!this.timePicker24Hour) { 614 var ampm = this.container.find('.left .ampmselect').val(); 615 if (ampm === 'PM' && hour < 12) 616 hour += 12; 617 if (ampm === 'AM' && hour === 12) 618 hour = 0; 619 } 620 } else { 621 hour = parseInt(this.container.find('.right .hourselect').val(), 10); 622 minute = parseInt(this.container.find('.right .minuteselect').val(), 10); 623 if (isNaN(minute)) { 624 minute = parseInt(this.container.find('.right .minuteselect option:last').val(), 10); 625 } 626 second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; 627 if (!this.timePicker24Hour) { 628 var ampm = this.container.find('.right .ampmselect').val(); 629 if (ampm === 'PM' && hour < 12) 630 hour += 12; 631 if (ampm === 'AM' && hour === 12) 632 hour = 0; 633 } 634 } 635 this.leftCalendar.month.hour(hour).minute(minute).second(second); 636 this.rightCalendar.month.hour(hour).minute(minute).second(second); 637 } 638 this.renderCalendar('left'); 639 this.renderCalendar('right'); 640 this.element.trigger('renderCalendar.daterangepicker', this); 641 642 //highlight any predefined range matching the current start and end dates 643 this.container.find('.ranges li').removeClass('active'); 644 if (this.endDate == null) return; 645 646 this.calculateChosenLabel(); 647 }, 648 649 renderCalendar: function(side) { 650 651 // 652 // Build the matrix of dates that will populate the calendar 653 // 654 var calendar = side == 'left' ? this.leftCalendar : this.rightCalendar; 655 var month = calendar.month.month(); 656 var year = calendar.month.year(); 657 var hour = calendar.month.hour(); 658 var minute = calendar.month.minute(); 659 var second = calendar.month.second(); 660 var daysInMonth = moment([year, month]).daysInMonth(); 661 var firstDay = moment([year, month, 1]); 662 var lastDay = moment([year, month, daysInMonth]); 663 var lastMonth = moment(firstDay).subtract(1, 'month').month(); 664 var lastYear = moment(firstDay).subtract(1, 'month').year(); 665 var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth(); 666 var dayOfWeek = firstDay.day(); 667 668 //initialize a 6 rows x 7 columns array for the calendar 669 var calendar = []; 670 calendar.firstDay = firstDay; 671 calendar.lastDay = lastDay; 672 673 for (var i = 0; i < 6; i++) { 674 calendar[i] = []; 675 } 676 677 //populate the calendar with date objects 678 var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1; 679 if (startDay > daysInLastMonth) 680 startDay -= 7; 681 682 if (dayOfWeek == this.locale.firstDay) 683 startDay = daysInLastMonth - 6; 684 685 var curDate = moment([lastYear, lastMonth, startDay, 12, minute, second]); 686 687 var col, row; 688 for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add(24, 'hour')) { 689 if (i > 0 && col % 7 === 0) { 690 col = 0; 691 row++; 692 } 693 calendar[row][col] = curDate.clone().hour(hour).minute(minute).second(second); 694 curDate.hour(12); 695 696 if (this.minDate && calendar[row][col].format('YYYY-MM-DD') == this.minDate.format('YYYY-MM-DD') && calendar[row][col].isBefore(this.minDate) && side == 'left') { 697 calendar[row][col] = this.minDate.clone(); 698 } 699 700 if (this.maxDate && calendar[row][col].format('YYYY-MM-DD') == this.maxDate.format('YYYY-MM-DD') && calendar[row][col].isAfter(this.maxDate) && side == 'right') { 701 calendar[row][col] = this.maxDate.clone(); 702 } 703 704 } 705 706 //make the calendar object available to hoverDate/clickDate 707 if (side == 'left') { 708 this.leftCalendar.calendar = calendar; 709 } else { 710 this.rightCalendar.calendar = calendar; 711 } 712 713 // 714 // Display the calendar 715 // 716 717 var minDate = side == 'left' ? this.minDate : this.startDate; 718 var maxDate = this.maxDate; 719 var selected = side == 'left' ? this.startDate : this.endDate; 720 var arrow = this.locale.direction == 'ltr' ? {left: 'chevron-left', right: 'chevron-right'} : {left: 'chevron-right', right: 'chevron-left'}; 721 722 var html = '<div class="drp-calendar-navigation"><div class="drp-calendar-navigation-left">'; 723 724 if ((!minDate || minDate.isBefore(calendar.firstDay)) && (!this.linkedCalendars || (side == 'left' || $(window).width() < 768))) { 725 html += '<div class="prev available"><span></span></div>'; 726 } else { 727 html += '<div class="inactive"></div>'; 728 } 729 730 var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY"); 731 732 if (this.showDropdowns) { 733 var currentMonth = calendar[1][1].month(); 734 var currentYear = calendar[1][1].year(); 735 var maxYear = (maxDate && maxDate.year()) || (this.maxYear); 736 //var minYear = (minDate && minDate.year()) || (this.minYear); 737 var minYear = this.minYear; 738 var inMinYear = currentYear == minYear; 739 var inMaxYear = currentYear == maxYear; 740 741 var monthHtml = '<select class="monthselect" id="monthselect-'+side+'">'; 742 for (var m = 0; m < 12; m++) { 743// if ((!inMinYear || (minDate && m >= minDate.month())) && (!inMaxYear || (maxDate && m <= maxDate.month()))) { 744 monthHtml += "<option value='" + m + "'" + 745 (m === currentMonth ? " selected='selected'" : "") + 746 ">" + this.locale.monthNames[m] + "</option>"; 747 /* } else { 748 monthHtml += "<option value='" + m + "'" + 749 (m === currentMonth ? " selected='selected'" : "") + 750 " disabled='disabled'>" + this.locale.monthNames[m] + "</option>"; 751 }*/ 752 } 753 monthHtml += "</select>"; 754 755 var yearHtml = '<select class="yearselect" id="yearselect-'+side+'">'; 756 for (var y = minYear; y <= maxYear; y++) { 757 yearHtml += '<option value="' + y + '"' + 758 (y === currentYear ? ' selected="selected"' : '') + 759 '>' + y + '</option>'; 760 } 761 yearHtml += '</select>'; 762 763 dateHtml = monthHtml + yearHtml; 764 } 765 766 html += '<div class="month">' + monthHtml + '</div></div>'; 767 html += '<div class="drp-calendar-navigation-right"><div class="year">' + yearHtml + '</div>'; 768 if ((!maxDate || maxDate.isAfter(calendar.lastDay)) && (!this.linkedCalendars || side == 'right' || this.singleDatePicker || $(window).width() < 768) && (currentYear < maxYear || (currentYear == maxYear && currentMonth < 11))) { 769 html += '<div class="next available"><span></span></div>'; 770 } else { 771 html += '<div class="inactive"></div>'; 772 } 773 774 html += '</div></div>'; 775 html += '<table class="table-condensed">'; 776 html += '<thead>'; 777 html += '<tr>'; 778 779 // add week number label 780 if (this.showWeekNumbers || this.showISOWeekNumbers) 781 html += '<th class="week">' + this.locale.weekLabel + '</th>'; 782 783 $.each(this.locale.daysOfWeek, function(index, dayOfWeek) { 784 html += '<th>' + dayOfWeek + '</th>'; 785 }); 786 787 html += '</tr>'; 788 html += '</thead>'; 789 html += '<tbody>'; 790 791 //adjust maxDate to reflect the maxSpan setting in order to 792 //grey out end dates beyond the maxSpan 793 if (this.endDate == null && this.maxSpan) { 794 var maxLimit = this.startDate.clone().add(this.maxSpan).endOf('day'); 795 if (!maxDate || maxLimit.isBefore(maxDate)) { 796 maxDate = maxLimit; 797 } 798 } 799 800 for (var row = 0; row < 6; row++) { 801 html += '<tr>'; 802 803 // add week number 804 if (this.showWeekNumbers) 805 html += '<td class="week">' + calendar[row][0].week() + '</td>'; 806 else if (this.showISOWeekNumbers) 807 html += '<td class="week">' + calendar[row][0].isoWeek() + '</td>'; 808 809 for (var col = 0; col < 7; col++) { 810 811 var classes = []; 812 813 //highlight today's date 814 if (calendar[row][col].isSame(new Date(), "day")) 815 classes.push('today'); 816 817 //highlight weekends 818 if (calendar[row][col].isoWeekday() > 5) 819 classes.push('weekend'); 820 821 //grey out the dates in other months displayed at beginning and end of this calendar 822 if (calendar[row][col].month() != calendar[1][1].month()) 823 classes.push('off', 'ends'); 824 825 //don't allow selection of dates before the minimum date 826 if (this.minDate && calendar[row][col].isBefore(this.minDate, 'day')) 827 classes.push('off', 'disabled'); 828 829 //don't allow selection of dates after the maximum date 830 if (maxDate && calendar[row][col].isAfter(maxDate, 'day')) 831 classes.push('off', 'disabled'); 832 833 //don't allow selection of date if a custom function decides it's invalid 834 if (this.isInvalidDate(calendar[row][col])) 835 classes.push('off', 'disabled'); 836 837 //highlight the currently selected start date 838 if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) 839 classes.push('active', 'start-date'); 840 841 //highlight the currently selected end date 842 if (this.endDate != null && calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) 843 classes.push('active', 'end-date'); 844 845 //highlight dates in-between the selected dates 846 if (this.endDate != null && calendar[row][col] > this.startDate && calendar[row][col] < this.endDate) 847 classes.push('in-range'); 848 849 //apply custom classes for this date 850 var isCustom = this.isCustomDate(calendar[row][col]); 851 if (isCustom !== false) { 852 if (typeof isCustom === 'string') 853 classes.push(isCustom); 854 else 855 Array.prototype.push.apply(classes, isCustom); 856 } 857 858 var cname = '', disabled = false; 859 for (var i = 0; i < classes.length; i++) { 860 cname += classes[i] + ' '; 861 if (classes[i] == 'disabled') 862 disabled = true; 863 } 864 if (!disabled) 865 cname += 'available'; 866 867 html += '<td class="' + cname.replace(/^\s+|\s+$/g, '') + '" data-title="' + 'r' + row + 'c' + col + '" title="'+calendar[row][col].date()+'">' + calendar[row][col].date() + '</td>'; 868 869 } 870 html += '</tr>'; 871 } 872 873 html += '</tbody>'; 874 html += '</table>'; 875 876 this.container.find('.drp-calendar.' + side + ' .calendar-table').html(html); 877 878 }, 879 880 renderTimePicker: function(side) { 881 882 // Don't bother updating the time picker if it's currently disabled 883 // because an end date hasn't been clicked yet 884 if (side == 'right' && !this.endDate) return; 885 886 var html, selected, minDate, maxDate = this.maxDate; 887 888 if (this.maxSpan && (!this.maxDate || this.startDate.clone().add(this.maxSpan).isBefore(this.maxDate))) 889 maxDate = this.startDate.clone().add(this.maxSpan); 890 891 if (side == 'left') { 892 selected = this.startDate.clone(); 893 minDate = this.minDate; 894 } else if (side == 'right') { 895 selected = this.endDate.clone(); 896 minDate = this.startDate; 897 898 //Preserve the time already selected 899 var timeSelector = this.container.find('.drp-calendar.right .calendar-time'); 900 if (timeSelector.html() != '') { 901 902 selected.hour(!isNaN(selected.hour()) ? selected.hour() : timeSelector.find('.hourselect option:selected').val()); 903 selected.minute(!isNaN(selected.minute()) ? selected.minute() : timeSelector.find('.minuteselect option:selected').val()); 904 selected.second(!isNaN(selected.second()) ? selected.second() : timeSelector.find('.secondselect option:selected').val()); 905 906 if (!this.timePicker24Hour) { 907 var ampm = timeSelector.find('.ampmselect option:selected').val(); 908 if (ampm === 'PM' && selected.hour() < 12) 909 selected.hour(selected.hour() + 12); 910 if (ampm === 'AM' && selected.hour() === 12) 911 selected.hour(0); 912 } 913 914 } 915 916 if (selected.isBefore(this.startDate)) 917 selected = this.startDate.clone(); 918 919 if (maxDate && selected.isAfter(maxDate)) 920 selected = maxDate.clone(); 921 922 } 923 924 // 925 // hours 926 // 927 928 html = '<select class="hourselect">'; 929 930 var start = this.timePicker24Hour ? 0 : 1; 931 var end = this.timePicker24Hour ? 23 : 12; 932 933 for (var i = start; i <= end; i++) { 934 var i_in_24 = i; 935 if (!this.timePicker24Hour) 936 i_in_24 = selected.hour() >= 12 ? (i == 12 ? 12 : i + 12) : (i == 12 ? 0 : i); 937 938 var time = selected.clone().hour(i_in_24); 939 var disabled = false; 940 if (minDate && time.minute(59).isBefore(minDate)) 941 disabled = true; 942 if (maxDate && time.minute(0).isAfter(maxDate)) 943 disabled = true; 944 945 if (i_in_24 == selected.hour() && !disabled) { 946 html += '<option value="' + i + '" selected="selected">' + i + '</option>'; 947 } else if (disabled) { 948 html += '<option value="' + i + '" disabled="disabled" class="disabled">' + i + '</option>'; 949 } else { 950 html += '<option value="' + i + '">' + i + '</option>'; 951 } 952 } 953 954 html += '</select> '; 955 956 // 957 // minutes 958 // 959 960 html += ': <select class="minuteselect">'; 961 962 for (var i = 0; i < 60; i += this.timePickerIncrement) { 963 var padded = i < 10 ? '0' + i : i; 964 var time = selected.clone().minute(i); 965 966 var disabled = false; 967 if (minDate && time.second(59).isBefore(minDate)) 968 disabled = true; 969 if (maxDate && time.second(0).isAfter(maxDate)) 970 disabled = true; 971 972 if (selected.minute() == i && !disabled) { 973 html += '<option value="' + i + '" selected="selected">' + padded + '</option>'; 974 } else if (disabled) { 975 html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>'; 976 } else { 977 html += '<option value="' + i + '">' + padded + '</option>'; 978 } 979 } 980 981 html += '</select> '; 982 983 // 984 // seconds 985 // 986 987 if (this.timePickerSeconds) { 988 html += ': <select class="secondselect">'; 989 990 for (var i = 0; i < 60; i++) { 991 var padded = i < 10 ? '0' + i : i; 992 var time = selected.clone().second(i); 993 994 var disabled = false; 995 if (minDate && time.isBefore(minDate)) 996 disabled = true; 997 if (maxDate && time.isAfter(maxDate)) 998 disabled = true; 999 1000 if (selected.second() == i && !disabled) { 1001 html += '<option value="' + i + '" selected="selected">' + padded + '</option>'; 1002 } else if (disabled) { 1003 html += '<option value="' + i + '" disabled="disabled" class="disabled">' + padded + '</option>'; 1004 } else { 1005 html += '<option value="' + i + '">' + padded + '</option>'; 1006 } 1007 } 1008 1009 html += '</select> '; 1010 } 1011 1012 // 1013 // AM/PM 1014 // 1015 1016 if (!this.timePicker24Hour) { 1017 html += '<select class="ampmselect">'; 1018 1019 var am_html = ''; 1020 var pm_html = ''; 1021 1022 if (minDate && selected.clone().hour(12).minute(0).second(0).isBefore(minDate)) 1023 am_html = ' disabled="disabled" class="disabled"'; 1024 1025 if (maxDate && selected.clone().hour(0).minute(0).second(0).isAfter(maxDate)) 1026 pm_html = ' disabled="disabled" class="disabled"'; 1027 1028 if (selected.hour() >= 12) { 1029 html += '<option value="AM"' + am_html + '>AM</option><option value="PM" selected="selected"' + pm_html + '>PM</option>'; 1030 } else { 1031 html += '<option value="AM" selected="selected"' + am_html + '>AM</option><option value="PM"' + pm_html + '>PM</option>'; 1032 } 1033 1034 html += '</select>'; 1035 } 1036 1037 this.container.find('.drp-calendar.' + side + ' .calendar-time').html(html); 1038 1039 }, 1040 1041 updateFormInputs: function() { 1042 1043 if (this.singleDatePicker || (this.endDate && (this.startDate.isBefore(this.endDate) || this.startDate.isSame(this.endDate)))) { 1044 this.container.find('button.applyBtn').prop('disabled', false); 1045 } else { 1046// if ( !this.endDate ) 1047// this.setEndDate(this.startDate.clone()) 1048 if (this.endDate && (!this.startDate.isBefore(this.endDate) || !this.startDate.isSame(this.endDate))) 1049 this.container.find('button.applyBtn').prop('disabled', true); 1050 } 1051 1052 }, 1053 1054 move: function() { 1055 var parentOffset = { top: 0, left: 0 }, 1056 containerTop, 1057 drops = this.drops; 1058 1059 var parentRightEdge = $(window).width(); 1060 if (!this.parentEl.is('body')) { 1061 parentOffset = { 1062 top: this.parentEl.offset().top - this.parentEl.scrollTop(), 1063 left: this.parentEl.offset().left - this.parentEl.scrollLeft() 1064 }; 1065 parentRightEdge = this.parentEl[0].clientWidth + this.parentEl.offset().left; 1066 } 1067 1068 switch (drops) { 1069 case 'auto': 1070 containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top; 1071 if (containerTop + this.container.outerHeight() >= this.parentEl[0].scrollHeight) { 1072 containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top; 1073 drops = 'up'; 1074 } 1075 break; 1076 case 'up': 1077 containerTop = this.element.offset().top - this.container.outerHeight() - parentOffset.top; 1078 break; 1079 default: 1080 containerTop = this.element.offset().top + this.element.outerHeight() - parentOffset.top; 1081 break; 1082 } 1083 1084 // Force the container to it's actual width 1085 this.container.css({ 1086 top: 0, 1087 left: 0, 1088 right: 'auto' 1089 }); 1090 var containerWidth = this.container.outerWidth(); 1091 1092 this.container.toggleClass('drop-up', drops == 'up'); 1093 1094 if (this.opens == 'left') { 1095 var containerRight = parentRightEdge - this.element.offset().left - this.element.outerWidth(); 1096 if (containerWidth + containerRight > $(window).width()) { 1097 this.container.css({ 1098 top: containerTop, 1099 right: 'auto', 1100 left: 9 1101 }); 1102 } else { 1103 this.container.css({ 1104 top: containerTop, 1105 right: containerRight, 1106 left: 'auto' 1107 }); 1108 } 1109 } else if (this.opens == 'center') { 1110 var containerLeft = this.element.offset().left - parentOffset.left + this.element.outerWidth() / 2 1111 - containerWidth / 2; 1112 if (containerLeft < 0) { 1113 this.container.css({ 1114 top: containerTop, 1115 right: 'auto', 1116 left: 9 1117 }); 1118 } else if (containerLeft + containerWidth > $(window).width()) { 1119 this.container.css({ 1120 top: containerTop, 1121 left: 'auto', 1122 right: 0 1123 }); 1124 } else { 1125 this.container.css({ 1126 top: containerTop, 1127 left: containerLeft, 1128 right: 'auto' 1129 }); 1130 } 1131 } else { 1132 var containerLeft = this.element.offset().left - parentOffset.left; 1133 if (containerLeft + containerWidth > $(window).width()) { 1134 this.container.css({ 1135 top: containerTop, 1136 left: 'auto', 1137 right: 0 1138 }); 1139 } else { 1140 this.container.css({ 1141 top: containerTop, 1142 left: containerLeft, 1143 right: 'auto' 1144 }); 1145 } 1146 } 1147 }, 1148 1149 show: function(e) { 1150 if (this.isShowing) return; 1151 1152 // Create a click proxy that is private to this instance of datepicker, for unbinding 1153 this._outsideClickProxy = $.proxy(function(e) { this.outsideClick(e); }, this); 1154 1155 // Bind global datepicker mousedown for hiding and 1156 $(document) 1157 .on('mousedown.daterangepicker', this._outsideClickProxy) 1158 // also support mobile devices 1159 .on('touchend.daterangepicker', this._outsideClickProxy) 1160 // also explicitly play nice with Bootstrap dropdowns, which stopPropagation when clicking them 1161 .on('click.daterangepicker', '[data-toggle=dropdown]', this._outsideClickProxy)
1162 // and also close when focus changes to outside the picker (eg. tabbing between controls) 1163 .on('focusin.daterangepicker', this._outsideClickProxy); 1164 1165 // Reposition the picker if the window is resized while it's open 1166 $(window).on('resize.daterangepicker', $.proxy(function(e) { this.move(e); }, this)); 1167 1168 this.oldStartDate = this.startDate.clone(); 1169 this.oldEndDate = this.endDate.clone(); 1170 this.previousRightTime = this.endDate.clone(); 1171 1172 this.updateView(); 1173 this.container.show(); 1174 this.move(); 1175 this.element.trigger('show.daterangepicker', this); 1176 this.isShowing = true; 1177 }, 1178 1179 hide: function(e) { 1180 if (!this.isShowing) return; 1181 1182 //incomplete date selection, revert to last values 1183 if (!this.endDate) { 1184 this.startDate = this.oldStartDate.clone(); 1185 this.endDate = this.oldEndDate.clone(); 1186 } 1187 1188 //if a new date range was selected, invoke the user callback function 1189 if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) 1190 this.callback(this.startDate.clone(), this.endDate.clone(), this.chosenLabel); 1191 1192 //if picker is attached to a text input, update it 1193 this.updateElement(); 1194 1195 $(document).off('.daterangepicker'); 1196 $(window).off('.daterangepicker'); 1197 this.container.hide(); 1198 this.element.trigger('hide.daterangepicker', this); 1199 this.isShowing = false; 1200 }, 1201 1202 toggle: function(e) { 1203 if (this.isShowing) { 1204 this.hide(); 1205 } else { 1206 this.show(); 1207 } 1208 }, 1209 1210 outsideClick: function(e) { 1211 if ( $(window).width() < 768 ) return; 1212 1213 var target = $(e.target); 1214 // if the page is clicked anywhere except within the daterangerpicker/button 1215 // itself then call this.hide() 1216 if ( 1217 // ie modal dialog fix 1218 e.type == "focusin" || 1219 target.closest(this.element).length || 1220 target.closest(this.container).length || 1221 target.closest('.calendar-table').length 1222 ) return; 1223 this.hide(); 1224 this.element.trigger('outsideClick.daterangepicker', this); 1225 }, 1226 1227 showCalendars: function() { 1228 this.container.addClass('show-calendar'); 1229 this.move(); 1230 this.element.trigger('showCalendar.daterangepicker', this); 1231 }, 1232 1233 hideCalendars: function() { 1234 this.container.removeClass('show-calendar'); 1235 this.element.trigger('hideCalendar.daterangepicker', this); 1236 }, 1237 1238 clickRange: function(e) { 1239 var label = e.target.getAttribute('data-range-key'); 1240 this.chosenLabel = label; 1241 if (label == this.locale.customRangeLabel) { 1242 1243 this.showCalendars(); 1244 } else { 1245 var dates = this.ranges[label]; 1246 this.startDate = dates[0]; 1247 this.endDate = dates[1]; 1248 1249 if (!this.timePicker) { 1250 this.startDate.startOf('day'); 1251 this.endDate.endOf('day'); 1252 } 1253 1254 if (!this.alwaysShowCalendars) 1255 this.hideCalendars(); 1256 this.clickApply(); 1257 } 1258 }, 1259 1260 clickPrev: function(e) { 1261 var cal = $(e.target).parents('.drp-calendar'); 1262 if (cal.hasClass('left')) { 1263 this.leftCalendar.month.subtract(1, 'month'); 1264 if (this.linkedCalendars) 1265 this.rightCalendar.month.subtract(1, 'month'); 1266 } else { 1267 this.rightCalendar.month.subtract(1, 'month'); 1268 } 1269 this.updateCalendars(); 1270 }, 1271 1272 clickNext: function(e) { 1273 var cal = $(e.target).parents('.drp-calendar'); 1274 if (cal.hasClass('left')) { 1275 this.leftCalendar.month.add(1, 'month'); 1276 } else { 1277 this.rightCalendar.month.add(1, 'month'); 1278 if (this.linkedCalendars) 1279 this.leftCalendar.month.add(1, 'month'); 1280 } 1281 this.updateCalendars(); 1282 }, 1283 1284 hoverDate: function(e) { 1285 1286 //ignore dates that can't be selected 1287 if (!$(e.target).hasClass('available')) return; 1288 1289 var title = $(e.target).attr('data-title'); 1290 var row = title.substr(1, 1); 1291 var col = title.substr(3, 1); 1292 var cal = $(e.target).parents('.drp-calendar'); 1293 var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; 1294 1295 //highlight the dates between the start date and the date being hovered as a potential end date 1296 var leftCalendar = this.leftCalendar; 1297 var rightCalendar = this.rightCalendar; 1298 var startDate = this.startDate; 1299 if (!this.endDate) { 1300 this.container.find('.drp-calendar tbody td').each(function(index, el) { 1301 1302 //skip week numbers, only look at dates 1303 if ($(el).hasClass('week')) return; 1304 1305 var title = $(el).attr('data-title'); 1306 var row = title.substr(1, 1); 1307 var col = title.substr(3, 1); 1308 var cal = $(el).parents('.drp-calendar'); 1309 var dt = cal.hasClass('left') ? leftCalendar.calendar[row][col] : rightCalendar.calendar[row][col]; 1310 1311 if ((dt.isAfter(startDate) && dt.isBefore(date)) || dt.isSame(date, 'day')) { 1312 $(el).addClass('in-range'); 1313 } else { 1314 $(el).removeClass('in-range'); 1315 } 1316 }); 1317 } 1318 1319 $('td').removeClass('last-in-range'); 1320 if (( $(e.target).prev().hasClass('in-range') || $(e.target).prev().hasClass('start-date') ) && !$(e.target).next().hasClass('in-range') && !$(e.target).prev().hasClass('end-date')) 1321 $(e.target).addClass('last-in-range'); 1322 1323 if ( $(e.target).prev().hasClass('in-range') && $(e.target).next().hasClass('in-range') ){ 1324 $(e.target).addClass('no-after') 1325 } 1326 1327 }, 1328 1329 clickDate: function(e) { 1330 1331 if (!$(e.target).hasClass('available')) return; 1332 1333 var title = $(e.target).attr('data-title'); 1334 var row = title.substr(1, 1); 1335 var col = title.substr(3, 1); 1336 var cal = $(e.target).parents('.drp-calendar'); 1337 var date = cal.hasClass('left') ? this.leftCalendar.calendar[row][col] : this.rightCalendar.calendar[row][col]; 1338 1339 var clickStart = cal.hasClass('left') ? true : false;
1340 1341 // 1342 // this function needs to do a few things: 1343 // * alternate between selecting a start and end date for the range, 1344 // * if the time picker is enabled, apply the hour/minute/second from the select boxes to the clicked date 1345 // * if autoapply is enabled, and an end date was chosen, apply the selection 1346 // * if single date picker mode, and time picker isn't enabled, apply the selection immediately 1347 // * if one of the inputs above the calendars was focused, cancel that manual input 1348 // 1349 1350 if ((this.endDate || date.isBefore(this.startDate, 'day')) && clickStart) { //picking start 1351 if (this.timePicker) { 1352 var hour = parseInt(this.container.find('.left .hourselect').val(), 10); 1353 if (!this.timePicker24Hour) { 1354 var ampm = this.container.find('.left .ampmselect').val(); 1355 if (ampm === 'PM' && hour < 12) 1356 hour += 12; 1357 if (ampm === 'AM' && hour === 12) 1358 hour = 0; 1359 } 1360 var minute = parseInt(this.container.find('.left .minuteselect').val(), 10); 1361 if (isNaN(minute)) { 1362 minute = parseInt(this.container.find('.left .minuteselect option:last').val(), 10); 1363 } 1364 var second = this.timePickerSeconds ? parseInt(this.container.find('.left .secondselect').val(), 10) : 0; 1365 date = date.clone().hour(hour).minute(minute).second(second); 1366 } 1367 this.endDate = null; 1368 this.setStartDate(date.clone()); 1369 this.dateRangeSelected = false; 1370 } else if (!this.endDate && date.isBefore(this.startDate)) { 1371 //special case: clicking the same date for start/end, 1372 //but the time of the end date is before the start date 1373 this.setEndDate(this.startDate.clone()); 1374 } else { // picking end 1375 if (this.timePicker) { 1376 var hour = parseInt(this.container.find('.right .hourselect').val(), 10); 1377 if (!this.timePicker24Hour) { 1378 var ampm = this.container.find('.right .ampmselect').val(); 1379 if (ampm === 'PM' && hour < 12) 1380 hour += 12; 1381 if (ampm === 'AM' && hour === 12) 1382 hour = 0; 1383 } 1384 var minute = parseInt(this.container.find('.right .minuteselect').val(), 10); 1385 if (isNaN(minute)) { 1386 minute = parseInt(this.container.find('.right .minuteselect option:last').val(), 10); 1387 } 1388 var second = this.timePickerSeconds ? parseInt(this.container.find('.right .secondselect').val(), 10) : 0; 1389 date = date.clone().hour(hour).minute(minute).second(second); 1390 } 1391 this.setEndDate(date.clone()); 1392 this.dateRangeSelected = true; 1393 if (this.autoApply) { 1394 this.calculateChosenLabel(); 1395 this.clickApply(); 1396 } 1397 } 1398 1399 if (this.singleDatePicker) { 1400 this.setEndDate(this.startDate); 1401 if (!this.timePicker && this.autoApply) 1402 this.clickApply(); 1403 } 1404 1405 this.updateView(); 1406 this.element.trigger('clickDate.daterangepicker', this); 1407 1408 1409 //This is to cancel the blur event handler if the mouse was in one of the inputs 1410 e.stopPropagation(); 1411 1412 }, 1413 1414 calculateChosenLabel: function () { 1415 var customRange = true; 1416 var i = 0; 1417 for (var range in this.ranges) { 1418 if (this.timePicker) { 1419 var format = this.timePickerSeconds ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD HH:mm"; 1420 //ignore times when comparing dates if time picker seconds
vendor: 8,040 bytes, lines 1420-1627
1420is not enabled 1421 if (this.startDate.format(format) == this.ranges[range][0].format(format) && this.endDate.format(format) == this.ranges[range][1].format(format)) { 1422 customRange = false; 1423 this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').attr('data-range-key'); 1424 break; 1425 } 1426 } else { 1427 //ignore times when comparing dates if time picker is not enabled 1428 if (this.startDate.format('YYYY-MM-DD') == this.ranges[range][0].format('YYYY-MM-DD') && this.endDate.format('YYYY-MM-DD') == this.ranges[range][1].format('YYYY-MM-DD')) { 1429 customRange = false; 1430 this.chosenLabel = this.container.find('.ranges li:eq(' + i + ')').addClass('active').attr('data-range-key'); 1431 break; 1432 } 1433 } 1434 i++; 1435 } 1436 if (customRange) { 1437 if (this.showCustomRangeLabel) { 1438 this.chosenLabel = this.container.find('.ranges li:last').addClass('active').attr('data-range-key'); 1439 } else { 1440 this.chosenLabel = null; 1441 } 1442 this.showCalendars(); 1443 } 1444 }, 1445 1446 clickApply: function(e) { 1447 if ( !this.endDate ) 1448 this.setEndDate( this.startDate.clone() ); 1449 this.hide(); 1450 this.element.trigger('apply.daterangepicker', this); 1451 }, 1452 1453 clickCancel: function(e) { 1454 this.startDate = this.oldStartDate; 1455 this.endDate = this.oldEndDate; 1456 this.hide(); 1457 this.element.trigger('cancel.daterangepicker', this); 1458 }, 1459 1460 monthOrYearChanged: function(e) { 1461 1462 var isLeft = $(e.target).closest('.drp-calendar').hasClass('left'), 1463 leftOrRight = isLeft ? 'left' : 'right', 1464 cal = this.container.find('.drp-calendar.'+leftOrRight); 1465 1466 // Month must be Number for new moment versions 1467 var month = parseInt(cal.find('.monthselect').val(), 10); 1468 var year = cal.find('.yearselect').val(); 1469 1470/* if (!isLeft) { 1471 if (year < this.startDate.year() || (year == this.startDate.year() && month < this.startDate.month())) { 1472 month = this.startDate.month(); 1473 year = this.startDate.year(); 1474 } 1475 } */ 1476 1477 if (this.minDate) { 1478 if (year < this.minDate.year() || (year == this.minDate.year() && month < this.minDate.month())) { 1479 month = this.minDate.month(); 1480 year = this.minDate.year(); 1481 } 1482 } 1483 1484 if (this.maxDate) { 1485 if (year > this.maxDate.year() || (year == this.maxDate.year() && month > this.maxDate.month())) { 1486 month = this.maxDate.month(); 1487 year = this.maxDate.year(); 1488 } 1489 } 1490 1491 if (isLeft) { 1492 this.leftCalendar.month.month(month).year(year); 1493 if (this.linkedCalendars) 1494 this.rightCalendar.month = this.leftCalendar.month.clone().add(1, 'month'); 1495 } else { 1496 this.rightCalendar.month.month(month).year(year); 1497 if (this.linkedCalendars) 1498 this.leftCalendar.month = this.rightCalendar.month.clone().subtract(1, 'month'); 1499 } 1500 this.updateCalendars(); 1501 }, 1502 1503 timeChanged: function(e) { 1504 1505 var cal = $(e.target).closest('.drp-calendar'), 1506 isLeft = cal.hasClass('left'); 1507 1508 var hour = parseInt(cal.find('.hourselect').val(), 10); 1509 var minute = parseInt(cal.find('.minuteselect').val(), 10); 1510 if (isNaN(minute)) { 1511 minute = parseInt(cal.find('.minuteselect option:last').val(), 10); 1512 } 1513 var second = this.timePickerSeconds ? parseInt(cal.find('.secondselect').val(), 10) : 0; 1514 1515 if (!this.timePicker24Hour) { 1516 var ampm = cal.find('.ampmselect').val(); 1517 if (ampm === 'PM' && hour < 12) 1518 hour += 12; 1519 if (ampm === 'AM' && hour === 12) 1520 hour = 0; 1521 } 1522 1523 if (isLeft) { 1524 var start = this.startDate.clone(); 1525 start.hour(hour); 1526 start.minute(minute); 1527 start.second(second); 1528 this.setStartDate(start); 1529 if (this.singleDatePicker) { 1530 this.endDate = this.startDate.clone(); 1531 } else if (this.endDate && this.endDate.format('YYYY-MM-DD') == start.format('YYYY-MM-DD') && this.endDate.isBefore(start)) { 1532 this.setEndDate(start.clone()); 1533 } 1534 } else if (this.endDate) { 1535 var end = this.endDate.clone(); 1536 end.hour(hour); 1537 end.minute(minute); 1538 end.second(second); 1539 this.setEndDate(end); 1540 } 1541 1542 //update the calendars so all clickable dates reflect the new time component 1543 this.updateCalendars(); 1544 1545 //update the form inputs above the calendars with the new time 1546 this.updateFormInputs(); 1547 1548 //re-render the time pickers because changing one selection can affect what's enabled in another 1549 this.renderTimePicker('left'); 1550 this.renderTimePicker('right'); 1551 1552 }, 1553 1554 elementChanged: function() { 1555 if (!this.element.is('input')) return; 1556 if (!this.element.val().length) return; 1557 1558 var dateString = this.element.val().split(this.locale.separator), 1559 start = null, 1560 end = null; 1561 1562 if (dateString.length === 2) { 1563 start = moment(dateString[0], this.locale.format); 1564 end = moment(dateString[1], this.locale.format); 1565 } 1566 1567 if (this.singleDatePicker || start === null || end === null) { 1568 start = moment(this.element.val(), this.locale.format); 1569 end = start; 1570 } 1571 1572 if (!start.isValid() || !end.isValid()) return; 1573 1574 this.setStartDate(start); 1575 this.setEndDate(end); 1576 this.updateView(); 1577 }, 1578 1579 keydown: function(e) { 1580 //hide on tab or enter 1581 if ((e.keyCode === 9) || (e.keyCode === 13)) { 1582 this.hide(); 1583 } 1584 1585 //hide on esc and prevent propagation 1586 if (e.keyCode === 27) { 1587 e.preventDefault(); 1588 e.stopPropagation(); 1589 1590 this.hide(); 1591 } 1592 }, 1593 1594 updateElement: function() { 1595 if (this.element.is('input') && this.autoUpdateInput) { 1596 var newValue = this.startDate.format(this.locale.format); 1597 if (!this.singleDatePicker) { 1598 newValue += this.locale.separator + this.endDate.format(this.locale.format); 1599 } 1600 if (newValue !== this.element.val()) { 1601 this.element.val(newValue).trigger('change'); 1602 } 1603 } 1604 }, 1605 1606 remove: function() { 1607 this.container.remove(); 1608 this.element.off('.daterangepicker'); 1609 this.element.removeData(); 1610 } 1611 1612 }; 1613 1614 $.fn.daterangepicker = function(options, callback) { 1615 var implementOptions = $.extend(true, {}, $.fn.daterangepicker.defaultOptions, options); 1616 this.each(function() { 1617 var el = $(this); 1618 if (el.data('daterangepicker')) 1619 el.data('daterangepicker').remove(); 1620 el.data('daterangepicker', new DateRangePicker(el, implementOptions, callback)); 1621 }); 1622 return this; 1623 }; 1624 1625 return DateRangePicker; 1626 1627}));
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.