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