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