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