1/** 2* @version: 1.2 3* @author: Dan Grossman http://www.dangrossman.info/ 4* 5* @Improved by KeenThemes for Metronic Bootstrap 3.0 6 7* @date: 2013-07-25 8* @copyright: Copyright (c) 2012-2013 Dan Grossman. All rights reserved. 9* @license: Licensed under Apache License v2.0. See http://www.apache.org/licenses/LICENSE-2.0 10* @website: http://www.improvely.com/ 11*/ 12!function ($) { 13 14 var DateRangePicker = function (element, options, cb) { 15 var hasOptions = typeof options == 'object'; 16 var localeObject; 17 18 //option defaults 19 20 this.startDate = moment().startOf('day'); 21 this.endDate = moment().startOf('day'); 22 this.minDate = false; 23 this.maxDate = false; 24 this.dateLimit = false; 25 26 this.showDropdowns = false; 27 this.showWeekNumbers = false; 28 this.timePicker = false; 29 this.timePickerIncrement = 30; 30 this.timePicker12Hour = true; 31 this.ranges = {}; 32 this.opens = 'right'; 33 34 this.buttonClasses = ['btn', 'btn-small']; 35 this.applyClass = 'green'; 36 this.cancelClass = 'default'; 37 38 this.format = 'MM/DD/YYYY'; 39 this.separator = ' - '; 40 41 this.locale = { 42 applyLabel: 'Apply', 43 cancelLabel: 'Cancel', 44 fromLabel: 'From', 45 toLabel: 'To', 46 weekLabel: 'W', 47 customRangeLabel: 'Custom Range', 48 daysOfWeek: moment()._lang._weekdaysMin.slice(), 49 monthNames: moment()._lang._monthsShort.slice(), 50 firstDay: 0 51 }; 52 53 this.cb = function () { }; 54 55 //element that triggered the date range picker 56 this.element = $(element); 57 58 if (this.element.hasClass('pull-right')) 59 this.opens = 'left'; 60 61 if (this.element.is('input')) { 62 this.element.on({ 63 click: $.proxy(this.show, this), 64 focus: $.proxy(this.show, this) 65 }); 66 } else { 67 this.element.on('click', $.proxy(this.show, this)); 68 } 69 70 localeObject = this.locale; 71 72 if (hasOptions) { 73 if (typeof options.locale == 'object') { 74 $.each(localeObject, function (property, value) { 75 localeObject[property] = options.locale[property] || value; 76 }); 77 } 78 79 if (options.applyClass) { 80 this.applyClass = options.applyClass; 81 } 82 83 if (options.cancelClass) { 84 this.cancelClass = options.cancelClass; 85 } 86 } 87 88 89 var DRPTemplate = '<div class="daterangepicker dropdown-menu">' + 90 '<div class="calendar left"></div>' + 91 '<div class="calendar right"></div>' + 92 '<div class="ranges">' + 93 '<div class="range_inputs">' + 94 '<div class="daterangepicker_start_input" style="float: left">' + 95 '<label for="daterangepicker_start">' + this.locale.fromLabel + '</label>' + 96 '<input class="input-mini" type="text" name="daterangepicker_start" value="" disabled="disabled" />' + 97 '</div>' + 98 '<div class="daterangepicker_end_input" style="float: left; padding-left: 11px">' + 99 '<label for="daterangepicker_end">' + this.locale.toLabel + '</label>' + 100 '<input class="input-mini" type="text" name="daterangepicker_end" value="" disabled="disabled" />' + 101 '</div>' + 102 '<button class="' + this.applyClass + ' applyBtn" disabled="disabled">' + this.locale.applyLabel + '</button> ' + 103 '<button class="' + this.cancelClass + ' cancelBtn">' + this.locale.cancelLabel + '</button>' + 104 '</div>' + 105 '</div>' + 106 '</div>'; 107 108 this.container = $(DRPTemplate).appendTo('body'); 109 110 if (hasOptions) { 111 112 if (typeof options.format == 'string') 113 this.format = options.format; 114 115 if (typeof options.separator == 'string') 116 this.separator = options.separator; 117 118 if (typeof options.startDate == 'string') 119 this.startDate = moment(options.startDate, this.format); 120 121 if (typeof options.endDate == 'string') 122 this.endDate = moment(options.endDate, this.format); 123 124 if (typeof options.minDate == 'string') 125 this.minDate = moment(options.minDate, this.format); 126 127 if (typeof options.maxDate == 'string') 128 this.maxDate = moment(options.maxDate, this.format); 129 130 if (typeof options.startDate == 'object') 131 this.startDate = moment(options.startDate); 132 133 if (typeof options.endDate == 'object') 134 this.endDate = moment(options.endDate); 135 136 if (typeof options.minDate == 'object') 137 this.minDate = moment(options.minDate); 138 139 if (typeof options.maxDate == 'object') 140 this.maxDate = moment(options.maxDate); 141 142 if (typeof options.ranges == 'object') { 143 for (var range in options.ranges) { 144 145 var start = moment(options.ranges[range][0]); 146 var end = moment(options.ranges[range][1]); 147 148 // If we have a min/max date set, bound this range 149 // to it, but only if it would otherwise fall 150 // outside of the min/max. 151 if (this.minDate && start.isBefore(this.minDate)) 152 start = moment(this.minDate); 153 154 if (this.maxDate && end.isAfter(this.maxDate)) 155 end = moment(this.maxDate); 156 157 // If the end of the range is before the minimum (if min is set) OR 158 // the start of the range is after the max (also if set) don't display this 159 // range option. 160 if ((this.minDate && end.isBefore(this.minDate)) || (this.maxDate && start.isAfter(this.maxDate))) { 161 continue; 162 } 163 164 this.ranges[range] = [start, end]; 165 } 166 167 var list = '<ul>'; 168 for (var range in this.ranges) { 169 list += '<li>' + range + '</li>'; 170 } 171 list += '<li>' + this.locale.customRangeLabel + '</li>'; 172 list += '</ul>'; 173 this.container.find('.ranges').prepend(list); 174 } 175 176 if (typeof options.dateLimit == 'object') 177 this.dateLimit = options.dateLimit; 178 179 // update day names order to firstDay 180 if (typeof options.locale == 'object') { 181 if (typeof options.locale.firstDay == 'number') { 182 this.locale.firstDay = options.locale.firstDay; 183 var iterator = options.locale.firstDay; 184 while (iterator > 0) { 185 this.locale.daysOfWeek.push(this.locale.daysOfWeek.shift()); 186 iterator--; 187 } 188 } 189 } 190 191 if (typeof options.opens == 'string') 192 this.opens = options.opens; 193 194 if (typeof options.showWeekNumbers == 'boolean') { 195 this.showWeekNumbers = options.showWeekNumbers; 196 } 197
198 if (typeof options.buttonClasses == 'string') { 199 this.buttonClasses = [options.buttonClasses]; 200 } 201 202 if (typeof options.buttonClasses == 'object') { 203 this.buttonClasses = options.buttonClasses; 204 } 205 206 if (typeof options.showDropdowns == 'boolean') { 207 this.showDropdowns = options.showDropdowns; 208 } 209 210 if (typeof options.timePicker == 'boolean') { 211 this.timePicker = options.timePicker; 212 } 213 214 if (typeof options.timePickerIncrement == 'number') { 215 this.timePickerIncrement = options.timePickerIncrement; 216 } 217 218 if (typeof options.timePicker12Hour == 'boolean') { 219 this.timePicker12Hour = options.timePicker12Hour; 220 } 221 222 } 223 224 if (!this.timePicker) { 225 this.startDate = this.startDate.startOf('day'); 226 this.endDate = this.endDate.startOf('day'); 227 } 228 229 //apply CSS classes to buttons 230 var c = this.container; 231 $.each(this.buttonClasses, function (idx, val) { 232 c.find('button').addClass(val); 233 }); 234 235 if (this.opens == 'right') { 236 //swap calendar positions 237 var left = this.container.find('.calendar.left'); 238 var right = this.container.find('.calendar.right'); 239 left.removeClass('left').addClass('right'); 240 right.removeClass('right').addClass('left'); 241 } 242 243 if (typeof options == 'undefined' || typeof options.ranges == 'undefined') { 244 this.container.find('.calendar').show(); 245 this.move(); 246 } 247 248 if (typeof cb == 'function') 249 this.cb = cb; 250 251 this.container.addClass('opens' + this.opens); 252 253 //try parse date if in text input 254 if (!hasOptions || (typeof options.startDate == 'undefined' && typeof options.endDate == 'undefined')) { 255 if ($(this.element).is('input[type=text]')) { 256 var val = $(this.element).val(); 257 var split = val.split(this.separator); 258 var start, end; 259 if (split.length == 2) { 260 start = moment(split[0], this.format); 261 end = moment(split[1], this.format); 262 } 263 if (start != null && end != null) { 264 this.startDate = start; 265 this.endDate = end; 266 } 267 } 268 } 269 270 //state 271 this.oldStartDate = this.startDate.clone(); 272 this.oldEndDate = this.endDate.clone(); 273 274 this.leftCalendar = { 275 month: moment([this.startDate.year(), this.startDate.month(), 1, this.startDate.hour(), this.startDate.minute()]), 276 calendar: [] 277 }; 278 279 this.rightCalendar = { 280 month: moment([this.endDate.year(), this.endDate.month(), 1, this.endDate.hour(), this.endDate.minute()]), 281 calendar: [] 282 }; 283 284 //event listeners 285 this.container.on('mousedown', $.proxy(this.mousedown, this)); 286 this.container.find('.calendar').on('click', '.prev', $.proxy(this.clickPrev, this)); 287 this.container.find('.calendar').on('click', '.next', $.proxy(this.clickNext, this)); 288 this.container.find('.ranges').on('click', 'button.applyBtn', $.proxy(this.clickApply, this)); 289 this.container.find('.ranges').on('click', 'button.cancelBtn', $.proxy(this.clickCancel, this)); 290 291 this.container.find('.ranges').on('click', '.daterangepicker_start_input', $.proxy(this.showCalendars, this)); 292 this.container.find('.ranges').on('click', '.daterangepicker_end_input', $.proxy(this.showCalendars, this)); 293 294 this.container.find('.calendar').on('click', 'td.available', $.proxy(this.clickDate, this)); 295 this.container.find('.calendar').on('mouseenter', 'td.available', $.proxy(this.enterDate, this)); 296 this.container.find('.calendar').on('mouseleave', 'td.available', $.proxy(this.updateView, this)); 297 298 this.container.find('.ranges').on('click', 'li', $.proxy(this.clickRange, this)); 299 this.container.find('.ranges').on('mouseenter', 'li', $.proxy(this.enterRange, this)); 300 this.container.find('.ranges').on('mouseleave', 'li', $.proxy(this.updateView, this)); 301 302 this.container.find('.calendar').on('change', 'select.yearselect', $.proxy(this.updateMonthYear, this)); 303 this.container.find('.calendar').on('change', 'select.monthselect', $.proxy(this.updateMonthYear, this)); 304 305 this.container.find('.calendar').on('change', 'select.hourselect', $.proxy(this.updateTime, this)); 306 this.container.find('.calendar').on('change', 'select.minuteselect', $.proxy(this.updateTime, this)); 307 this.container.find('.calendar').on('change', 'select.ampmselect', $.proxy(this.updateTime, this)); 308 309 this.element.on('keyup', $.proxy(this.updateFromControl, this)); 310 311 this.updateView(); 312 this.updateCalendars(); 313 314 }; 315 316 DateRangePicker.prototype = { 317 318 constructor: DateRangePicker, 319 320 mousedown: function (e) { 321 e.stopPropagation(); 322 }, 323 324 updateView: function () { 325 this.leftCalendar.month.month(this.startDate.month()).year
325(this.startDate.year()); 326 this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()); 327 328 this.container.find('input[name=daterangepicker_start]').val(this.startDate.format(this.format)); 329 this.container.find('input[name=daterangepicker_end]').val(this.endDate.format(this.format)); 330 331 if (this.startDate.isSame(this.endDate) || this.startDate.isBefore(this.endDate)) { 332 this.container.find('button.applyBtn').removeAttr('disabled'); 333 } else { 334 this.container.find('button.applyBtn').attr('disabled', 'disabled'); 335 } 336 }, 337 338 updateFromControl: function () { 339 if (!this.element.is('input')) return; 340 if (!this.element.val().length) return; 341 342 var dateString = this.element.val().split(this.separator); 343 var start = moment(dateString[0], this.format); 344 var end = moment(dateString[1], this.format); 345 346 if (start == null || end == null) return; 347 if (end.isBefore(start)) return; 348 349 this.startDate = start; 350 this.endDate = end; 351 352 this.notify(); 353 this.updateCalendars(); 354 }, 355 356 notify: function () { 357 this.updateView(); 358 this.cb(this.startDate, this.endDate); 359 }, 360 361 move: function () { 362 var minWidth = $(this.container).find('.ranges').outerWidth(); 363 if ($(this.container).find('.calendar').is(':visible')) { 364 var padding = 24; // FIXME: this works for the default styling, but isn't flexible 365 minWidth += $(this.container).find('.calendar').outerWidth() * 2 + padding; 366 } 367 if (this.opens == 'left') { 368 this.container.css({ 369 top: this.element.offset().top + this.element.outerHeight(), 370 right: $(window).width() - this.element.offset().left - this.element.outerWidth(), 371 left: 'auto', 372 'min-width': minWidth 373 }); 374 if (this.container.offset().left < 0) { 375 this.container.css({ 376 right: 'auto', 377 left: 9 378 }); 379 } 380 } else { 381 this.container.css({ 382 top: this.element.offset().top + this.element.outerHeight(), 383 left: this.element.offset().left, 384 right: 'auto', 385 'min-width': minWidth 386 }); 387 if (this.container.offset().left + this.container.outerWidth() > $(window).width()) { 388 this.container.css({ 389 left: 'auto', 390 right: 0 391 }); 392 } 393 } 394 }, 395 396 show: function (e) { 397 this.container.show(); 398 this.move(); 399 400 if (e) { 401 e.stopPropagation(); 402 e.preventDefault(); 403 } 404 405 $(document).on('mousedown', $.proxy(this.hide, this)); 406 this.element.trigger('shown', {target: e.target, picker: this}); 407 }, 408 409 hide: function (e) { 410 this.container.hide(); 411 412 if (!this.startDate.isSame(this.oldStartDate) || !this.endDate.isSame(this.oldEndDate)) 413 this.notify(); 414 415 this.oldStartDate = this.startDate.clone(); 416 this.oldEndDate = this.endDate.clone(); 417 418 $(document).off('mousedown', this.hide); 419 this.element.trigger('hidden', { picker: this }); 420 }, 421 422 enterRange: function (e) { 423 var label = e.target.innerHTML; 424 if (label == this.locale.customRangeLabel) { 425 this.updateView(); 426 } else { 427 var dates = this.ranges[label]; 428 this.container.find('input[name=daterangepicker_start]').val(dates[0].format(this.format)); 429 this.container.find('input[name=daterangepicker_end]').val(dates[1].format(this.format)); 430 } 431 }, 432 433 showCalendars: function() { 434 this.container.find('.calendar').show(); 435 this.move(); 436 }, 437 438 updateInputText: function() { 439 if (this.element.is('input')) 440 this.element.val(this.startDate.format(this.format) + this.separator + this.endDate.format(this.format)); 441 }, 442 443 clickRange: function (e) { 444 var label = e.target.innerHTML; 445 if (label == this.locale.customRangeLabel) { 446 this.showCalendars(); 447 } else { 448 var dates = this.ranges[label]; 449 450 this.startDate = dates[0]; 451 this.endDate = dates[1]; 452 453 if (!this.timePicker) { 454 this.startDate.startOf('day'); 455 this.endDate.startOf('day'); 456 } 457 458 this.leftCalendar.month.month(this.startDate.month()).year
458(this.startDate.year()).hour(this.startDate.hour()).minute(this.startDate.minute()); 459 this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()).hour(this.endDate.hour()).minute(this.endDate.minute()); 460 this.updateCalendars(); 461 462 this.updateInputText(); 463 464 this.container.find('.calendar').hide(); 465 this.hide(); 466 } 467 }, 468 469 clickPrev: function (e) { 470 var cal = $(e.target).parents('.calendar'); 471 if (cal.hasClass('left')) { 472 this.leftCalendar.month.subtract('month', 1); 473 } else { 474 this.rightCalendar.month.subtract('month', 1); 475 } 476 this.updateCalendars(); 477 }, 478 479 clickNext: function (e) { 480 var cal = $(e.target).parents('.calendar'); 481 if (cal.hasClass('left')) { 482 this.leftCalendar.month.add('month', 1); 483 } else { 484 this.rightCalendar.month.add('month', 1); 485 } 486 this.updateCalendars(); 487 }, 488 489 enterDate: function (e) { 490 491 var title = $(e.target).attr('data-title'); 492 var row = title.substr(1, 1); 493 var col = title.substr(3, 1); 494 var cal = $(e.target).parents('.calendar'); 495 496 if (cal.hasClass('left')) { 497 this.container.find('input[name=daterangepicker_start]').val(this.leftCalendar.calendar[row][col].format(this.format)); 498 } else { 499 this.container.find('input[name=daterangepicker_end]').val(this.rightCalendar.calendar[row][col].format(this.format)); 500 } 501 502 }, 503 504 clickDate: function (e) { 505 var title = $(e.target).attr('data-title'); 506 var row = title.substr(1, 1); 507 var col = title.substr(3, 1); 508 var cal = $(e.target).parents('.calendar'); 509 510 if (cal.hasClass('left')) { 511 var startDate = this.leftCalendar.calendar[row][col]; 512 var endDate = this.endDate; 513 if (typeof this.dateLimit == 'object') { 514 var maxDate = moment(startDate).add(this.dateLimit).startOf('day'); 515 if (endDate.isAfter(maxDate)) { 516 endDate = maxDate; 517 } 518 } 519 } else { 520 var startDate = this.startDate; 521 var endDate = this.rightCalendar.calendar[row][col]; 522 if (typeof this.dateLimit == 'object') { 523 var minDate = moment(endDate).subtract(this.dateLimit).startOf('day'); 524 if (startDate.isBefore(minDate)) { 525 startDate = minDate; 526 } 527 } 528 } 529 530 cal.find('td').removeClass('active'); 531 532 if (startDate.isSame(endDate) || startDate.isBefore(endDate)) { 533 $(e.target).addClass('active'); 534 this.startDate = startDate; 535 this.endDate = endDate; 536 } else if (startDate.isAfter(endDate)) { 537 $(e.target).addClass('active'); 538 this.startDate = startDate; 539 this.endDate = moment(startDate).add('day', 1).startOf('day'); 540 } 541 542 this.leftCalendar.month.month(this.startDate.month()).year(this.startDate.year()); 543 this.rightCalendar.month.month(this.endDate.month()).year(this.endDate.year()); 544 this.updateCalendars(); 545 }, 546 547 clickApply: function (e) { 548 this.updateInputText(); 549 this.hide(); 550 }, 551 552 clickCancel: function (e) { 553 this.startDate = this.oldStartDate; 554 this.endDate = this.oldEndDate; 555 this.updateView(); 556 this.updateCalendars(); 557 this.hide(); 558 }, 559 560 updateMonthYear: function (e) { 561 562 var isLeft = $(e.target).closest('.calendar').hasClass('left'); 563 var cal = this.container.find('.calendar.left'); 564 if (!isLeft) 565 cal = this.container.find('.calendar.right'); 566
567 var month = cal.find('.monthselect').val(); 568 var year = cal.find('.yearselect').val(); 569 570 if (isLeft) { 571 this.leftCalendar.month.month(month).year(year); 572 } else { 573 this.rightCalendar.month.month(month).year(year); 574 } 575 576 this.updateCalendars(); 577 578 }, 579 580 updateTime: function(e) { 581 582 var isLeft = $(e.target).closest('.calendar').hasClass('left'); 583 var cal = this.container.find('.calendar.left'); 584 if (!isLeft) 585 cal = this.container.find('.calendar.right'); 586 587 var hour = parseInt(cal.find('.hourselect').val()); 588 var minute = parseInt(cal.find('.minuteselect').val()); 589 590 if (this.timePicker12Hour) { 591 var ampm = cal.find('.ampmselect').val(); 592 if (ampm == 'PM' && hour < 12) 593 hour += 12; 594 if (ampm == 'AM' && hour == 12) 595 hour = 0; 596 } 597 598 if (isLeft) { 599 var start = this.startDate; 600 start.hour(hour); 601 start.minute(minute); 602 this.startDate = start; 603 this.leftCalendar.month.hour(hour).minute(minute); 604 } else { 605 var end = this.endDate; 606 end.hour(hour); 607 end.minute(minute); 608 this.endDate = end; 609 this.rightCalendar.month.hour(hour).minute(minute); 610 } 611 612 this.updateCalendars(); 613 614 }, 615 616 updateCalendars: function () { 617 this.leftCalendar.calendar = this.buildCalendar(this.leftCalendar.month.month(), this.leftCalendar.month.year(), this.leftCalendar.month.hour(), this.leftCalendar.month.minute(), 'left'); 618 this.rightCalendar.calendar = this.buildCalendar(this.rightCalendar.month.month(), this.rightCalendar.month.year(), this.rightCalendar.month.hour(), this.rightCalendar.month.minute(), 'right'); 619 this.container.find('.calendar.left').html(this.renderCalendar(this.leftCalendar.calendar, this.startDate, this.minDate, this.maxDate)); 620 this.container.find('.calendar.right').html(this.renderCalendar(this.rightCalendar.calendar, this.endDate, this.startDate, this.maxDate)); 621 622 this.container.find('.ranges li').removeClass('active'); 623 var customRange = true; 624 var i = 0; 625 for (var range in this.ranges) { 626 if (this.timePicker) { 627 if (this.startDate.isSame(this.ranges[range][0]) && this.endDate.isSame(this.ranges[range][1])) { 628 customRange = false; 629 this.container.find('.ranges li:eq(' + i + ')').addClass('active'); 630 } 631 } else { 632 //ignore times when comparing dates if time picker is not enabled 633 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')) { 634 customRange = false; 635 this.container.find('.ranges li:eq(' + i + ')').addClass('active'); 636 } 637 } 638 i++; 639 } 640 if (customRange) 641 this.container.find('.ranges li:last').addClass('active'); 642 }, 643 644 buildCalendar: function (month, year, hour, minute, side) { 645 646 var firstDay = moment([year, month, 1]); 647 var lastMonth = moment(firstDay).subtract('month', 1).month(); 648 var lastYear = moment(firstDay).subtract('month', 1).year(); 649 650 var daysInLastMonth = moment([lastYear, lastMonth]).daysInMonth(); 651 652 var dayOfWeek = firstDay.day(); 653 654 //initialize a 6 rows x 7 columns array for the calendar 655 var calendar = []; 656 for (var i = 0; i < 6; i++) { 657 calendar[i] = []; 658 } 659 660 //populate the calendar with date objects 661 var startDay = daysInLastMonth - dayOfWeek + this.locale.firstDay + 1; 662 if (startDay > daysInLastMonth) 663 startDay -= 7; 664 665 if (dayOfWeek == this.locale.firstDay) 666 startDay = daysInLastMonth - 6; 667 668 var curDate = moment([lastYear, lastMonth, startDay, hour, minute]); 669 for (var i = 0, col = 0, row = 0; i < 42; i++, col++, curDate = moment(curDate).add('day', 1)) { 670 if (i > 0 && col % 7 == 0) { 671 col = 0; 672 row++; 673 } 674 calendar[row][col] = curDate; 675 } 676 677 return calendar; 678 679 }, 680 681 renderDropdowns: function (selected, minDate, maxDate) { 682 var currentMonth = selected.month(); 683 var monthHtml = '<select class="monthselect">'; 684 var inMinYear = false;
685 var inMaxYear = false; 686 687 for (var m = 0; m < 12; m++) { 688 if ((!inMinYear || m >= minDate.month()) && (!inMaxYear || m <= maxDate.month())) { 689 monthHtml += "<option value='" + m + "'" + 690 (m === currentMonth ? " selected='selected'" : "") + 691 ">" + this.locale.monthNames[m] + "</option>"; 692 } 693 } 694 monthHtml += "</select>"; 695 696 var currentYear = selected.year(); 697 var maxYear = (maxDate && maxDate.year()) || (currentYear + 5); 698 var minYear = (minDate && minDate.year()) || (currentYear - 50); 699 var yearHtml = '<select class="yearselect">' 700 701 for (var y = minYear; y <= maxYear; y++) { 702 yearHtml += '<option value="' + y + '"' + 703 (y === currentYear ? ' selected="selected"' : '') + 704 '>' + y + '</option>'; 705 } 706 707 yearHtml += '</select>'; 708 709 return monthHtml + yearHtml; 710 }, 711 712 renderCalendar: function (calendar, selected, minDate, maxDate) { 713 714 var html = '<div class="calendar-date">'; 715 html += '<table class="table-condensed">'; 716 html += '<thead>'; 717 html += '<tr>'; 718 719 // add empty cell for week number 720 if (this.showWeekNumbers) 721 html += '<th></th>'; 722 723 if (!minDate || minDate.isBefore(calendar[1][1])) { 724 html += '<th class="prev available"><i class="fa fa-angle-left"></i></th>'; 725 } else { 726 html += '<th></th>'; 727 } 728 729 var dateHtml = this.locale.monthNames[calendar[1][1].month()] + calendar[1][1].format(" YYYY"); 730 731 if (this.showDropdowns) { 732 dateHtml = this.renderDropdowns(calendar[1][1], minDate, maxDate); 733 } 734 735 html += '<th colspan="5" style="width: auto">' + dateHtml + '</th>'; 736 if (!maxDate || maxDate.isAfter(calendar[1][1])) { 737 html += '<th class="next available"><i class="fa fa-angle-right"></i></th>'; 738 } else { 739 html += '<th></th>'; 740 } 741 742 html += '</tr>'; 743 html += '<tr>'; 744 745 // add week number label 746 if (this.showWeekNumbers) 747 html += '<th class="week">' + this.locale.weekLabel + '</th>'; 748 749 $.each(this.locale.daysOfWeek, function (index, dayOfWeek) { 750 html += '<th>' + dayOfWeek + '</th>'; 751 }); 752 753 html += '</tr>'; 754 html += '</thead>'; 755 html += '<tbody>'; 756 757 for (var row = 0; row < 6; row++) { 758 html += '<tr>'; 759 760 // add week number 761 if (this.showWeekNumbers) 762 html += '<td class="week">' + calendar[row][0].week() + '</td>'; 763 764 for (var col = 0; col < 7; col++) { 765 var cname = 'available '; 766 cname += (calendar[row][col].month() == calendar[1][1].month()) ? '' : 'off'; 767 768 if ((minDate && calendar[row][col].isBefore(minDate)) || (maxDate && calendar[row][col].isAfter(maxDate))) { 769 cname = ' off disabled '; 770 } else if (calendar[row][col].format('YYYY-MM-DD') == selected.format('YYYY-MM-DD')) { 771 cname += ' active '; 772 if (calendar[row][col].format('YYYY-MM-DD') == this.startDate.format('YYYY-MM-DD')) { 773 cname += ' start-date '; 774 } 775 if (calendar[row][col].format('YYYY-MM-DD') == this.endDate.format('YYYY-MM-DD')) { 776 cname += ' end-date '; 777 } 778 } else if (calendar[row][col] >= this.startDate && calendar[row][col] <= this.endDate) { 779 cname += ' in-range '; 780 if (calendar[row][col].isSame(this.startDate)) { cname += ' start-date '; } 781 if (calendar[row][col].isSame(this.endDate)) { cname += ' end-date '; } 782 } 783 784 var title = 'r' + row + 'c' + col; 785 html += '<td class="' + cname.replace(/\s+/g, ' ').replace(/^\s?(.*?)\s?$/, '$1') + '" data-title="' + title + '">' + calendar[row][col].date() + '</td>'; 786 } 787 html += '</tr>'; 788 } 789 790 html += '</tbody>'; 791 html += '</table>'; 792 html += '</div>'; 793 794 if (this.timePicker) { 795 796 html += '<div class="calendar-time">'; 797 html += '<select class="hourselect">'; 798 var start = 0; 799 var end = 23; 800 var selected_hour = selected.hour(); 801 if (this.timePicker12Hour) { 802 start = 1; 803 end = 12; 804 if (selected_hour >= 12) 805 selected_hour -= 12; 806 if (selected_hour == 0) 807 selected_hour = 12; 808 } 809 810 for (var i = start; i <= end; i++) { 811 if (i == selected_hour) { 812 html += '<option value="' + i + '" selected="selected">' + i + '</option>'; 813 } else { 814 html += '<option value="' + i + '">' + i + '</option>'; 815 } 816 } 817 818 html += '</select> : '; 819 820 html += '<select class="minuteselect">'; 821 822 for (var i = 0; i < 60; i += this.timePickerIncrement) { 823 var num = i; 824 if (num < 10) 825 num = '0' + num; 826 if (i == selected.minute()) { 827 html += '<option value="' + i + '" selected="selected">' + num + '</option>'; 828 } else { 829 html += '<option value="' + i + '">' + num + '</option>'; 830 } 831 } 832 833 html += '</select> '; 834 835 if (this.timePicker12Hour) { 836 html += '<select class="ampmselect">'; 837 if (selected.hour() >= 12) { 838 html += '<option value="AM">AM</option><option value="PM" selected="selected">PM</option>'; 839 } else { 840 html += '<option value="AM" selected="selected">AM</option><option value="PM">PM</option>'; 841 } 842 html += '</select>'; 843 } 844 845 html += '</div>'; 846 847 } 848 849 return html; 850 851 } 852 853 }; 854 855 $.fn.daterangepicker = function (options, cb) { 856 this.each(function () { 857 var el = $(this); 858 if (!el.data('daterangepicker')) 859 el.data('daterangepicker', new DateRangePicker(el, options, cb)); 860 }); 861 return this; 862 }; 863 864}(window.jQuery);
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.