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