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