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