1/* ========================================================= 2 * bootstrap-datepicker.js 3 * http://www.eyecon.ro/bootstrap-datepicker 4 * ========================================================= 5 * Copyright 2012 Stefan Petre 6 * Improvements by Andrew Rowls 7 * Improvements By Keenthemes for Boostrap 3.0 support 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 * ========================================================= */ 21 22(function( $ ) { 23 24 var $window = $(window); 25 26 function UTCDate(){ 27 return new Date(Date.UTC.apply(Date, arguments)); 28 } 29 function UTCToday(){ 30 var today = new Date(); 31 return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()); 32 } 33 34 35 // Picker object 36 37 var Datepicker = function(element, options) { 38 var that = this; 39 40 this._process_options(options); 41 42 this.element = $(element); 43 this.isInline = false; 44 this.isInput = this.element.is('input'); 45 this.component = this.element.is('.date') ? this.element.find('.input-group-btn, .btn') : false; 46 this.hasInput = this.component && this.element.find('input').length; 47 if(this.component && this.component.length === 0) 48 this.component = false; 49 50 this.picker = $(DPGlobal.template); 51 this._buildEvents(); 52 this._attachEvents(); 53 54 if(this.isInline) { 55 this.picker.addClass('datepicker-inline').appendTo(this.element); 56 } else { 57 this.picker.addClass('datepicker-dropdown dropdown-menu'); 58 } 59 60 if (this.o.rtl){ 61 this.picker.addClass('datepicker-rtl'); 62 this.picker.find('.prev i, .next i') 63 .toggleClass('icon-angle-left icon-angle-right'); 64 } 65 66 67 this.viewMode = this.o.startView; 68 69 if (this.o.calendarWeeks) 70 this.picker.find('tfoot th.today') 71 .attr('colspan', function(i, val){ 72 return parseInt(val) + 1; 73 }); 74 75 this._allow_update = false; 76 77 this.setStartDate(this._o.startDate); 78 this.setEndDate(this._o.endDate); 79 this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled); 80 81 this.fillDow(); 82 this.fillMonths(); 83 84 this._allow_update = true; 85 86 this.update(); 87 this.showMode(); 88 89 if(this.isInline) { 90 this.show(); 91 } 92 }; 93 94 Datepicker.prototype = { 95 constructor: Datepicker, 96 97 _process_options: function(opts){ 98 // Store raw options for reference 99 this._o = $.extend({}, this._o, opts); 100 // Processed options 101 var o = this.o = $.extend({}, this._o); 102 103 // Check if "de-DE" style date is available, if not language should 104 // fallback to 2 letter code eg "de" 105 var lang = o.language; 106 if (!dates[lang]) { 107 lang = lang.split('-')[0]; 108 if (!dates[lang]) 109 lang = defaults.language; 110 } 111 o.language = lang; 112 113 switch(o.startView){ 114 case 2: 115 case 'decade': 116 o.startView = 2; 117 break; 118 case 1: 119 case 'year': 120 o.startView = 1; 121 break; 122 default: 123 o.startView = 0; 124 } 125 126 switch (o.minViewMode) { 127 case 1: 128 case 'months': 129 o.minViewMode = 1; 130 break; 131 case 2: 132 case 'years': 133 o.minViewMode = 2; 134 break; 135 default: 136 o.minViewMode = 0; 137 } 138 139 o.startView = Math.max(o.startView, o.minViewMode); 140 141 o.weekStart %= 7; 142 o.weekEnd = ((o.weekStart + 6) % 7); 143 144 var format = DPGlobal.parseFormat(o.format); 145 if (o.startDate !== -Infinity) { 146 if (!!o.startDate) { 147 if (o.startDate instanceof Date) 148 o.startDate = this._local_to_utc(this._zero_time(o.startDate)); 149 else 150 o.startDate = DPGlobal.parseDate(o.startDate, format, o.language); 151 } else { 152 o.startDate = -Infinity; 153 } 154 } 155 if (o.endDate !== Infinity) { 156 if (!!o.endDate) { 157 if (o.endDate instanceof Date) 158 o.endDate = this._local_to_utc(this._zero_time(o.endDate)); 159 else 160 o.endDate = DPGlobal.parseDate(o.endDate, format, o.language); 161 } else { 162 o.endDate = Infinity; 163 } 164 } 165 166 o.daysOfWeekDisabled = o.daysOfWeekDisabled||[]; 167 if (!$.isArray(o.daysOfWeekDisabled)) 168 o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/); 169 o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function (d) { 170 return parseInt(d, 10); 171 }); 172 173 var plc = String(o.orientation).toLowerCase().split(/\s+/g), 174 _plc = o.orientation.toLowerCase(); 175 plc = $.grep(plc, function(word){ 176 return (/^auto|left|right|top|bottom$/).test(word); 177 }); 178 o.orientation = {x: 'auto', y: 'auto'}; 179 if (!_plc || _plc === 'auto') 180 ; // no action 181 else if (plc.length === 1){ 182 switch(plc[0]){ 183 case 'top': 184 case 'bottom': 185 o.orientation.y = plc[0]; 186 break; 187 case 'left': 188 case 'right': 189 o.orientation.x = plc[0]; 190 break; 191 } 192 } 193 else { 194 _plc = $.grep(plc, function(word){ 195 return (/^left|right$/).test(word); 196 }); 197 o.orientation.x = _plc[0] || 'auto'; 198 199 _plc = $.grep(plc, function(word){ 200 return (/^top|bottom$/).test(word); 201 }); 202 o.orientation.y = _plc[0] || 'auto'; 203 } 204 }, 205 _events: [], 206 _secondaryEvents: [], 207 _applyEvents: function(evs){ 208 for (var i=0, el, ev; i<evs.length; i++){ 209 el = evs[i][0]; 210 ev = evs[i][1]; 211 el.on(ev); 212 } 213 }, 214 _unapplyEvents: function(evs){ 215 for (var i=0, el, ev; i<evs.length; i++){ 216 el = evs[i][0]; 217 ev = evs[i][1]; 218 el.off(ev); 219 } 220 }, 221 _buildEvents: function(){ 222 if (this.isInput) { // single input 223 this._events = [ 224 [this.element, { 225 focus: $.proxy(this.show, this), 226 keyup: $.proxy(this.update, this), 227 keydown: $.proxy(this.keydown, this) 228 }] 229 ]; 230 } 231 else if (this.component && this.hasInput){ // component: input + button 232 this._events = [ 233 // For components that are not readonly, allow keyboard nav 234 [this.element.find('input'), { 235 focus: $.proxy(this.show, this), 236 keyup: $.proxy(this.update, this), 237 keydown: $.proxy(this.keydown, this) 238 }], 239 [this.component, { 240 click: $.proxy(this.show, this) 241 }] 242 ]; 243 } 244 else if (this.element.is('div')) { // inline datepicker 245 this.isInline = true; 246 } 247 else { 248 this._events = [ 249 [this.element, { 250 click: $.proxy(this.show, this) 251 }] 252 ]; 253 } 254 255 this._secondaryEvents = [ 256 [this.picker, { 257 click: $.proxy(this.click, this) 258 }], 259 [$(window), { 260 resize: $.proxy(this.place, this) 261 }], 262 [$(document), { 263 mousedown: $.proxy(function (e) { 264 // Clicked outside the datepicker, hide it 265 if (!( 266 this.element.is(e.target) || 267 this.element.find(e.target).length || 268 this.picker.is(e.target) || 269 this.picker.find(e.target).length 270 )) { 271 this.hide(); 272 } 273 }, this) 274 }] 275 ]; 276 }, 277 _attachEvents: function(){ 278 this._detachEvents(); 279 this._applyEvents(this._events); 280 }, 281 _detachEvents: function(){ 282 this._unapplyEvents(this._events); 283 }, 284 _attachSecondaryEvents: function(){ 285 this._detachSecondaryEvents(); 286 this._applyEvents(this._secondaryEvents); 287 }, 288 _detachSecondaryEvents: function(){ 289 this._unapplyEvents(this._secondaryEvents); 290 }, 291 _trigger: function(event, altdate){ 292 var date = altdate || this.date, 293 local_date = this._utc_to_local(date); 294 295 this.element.trigger({ 296 type: event, 297 date: local_date, 298 format: $.proxy(function(altformat){ 299 var format = altformat || this.o.format; 300 return DPGlobal.formatDate(date, format, this.o.language); 301 }, this) 302 }); 303 }, 304 305 show: function(e) { 306 if (!this.isInline) 307 this.picker.appendTo('body'); 308 this.picker.show(); 309 this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); 310 this.place(); 311 this._attachSecondaryEvents(); 312 if (e) { 313 e.preventDefault(); 314 } 315 this._trigger('show'); 316 }, 317 318 hide: function(e){ 319 if(this.isInline) return; 320 if (!this.picker.is(':visible')) return; 321 this.picker.hide().detach(); 322 this._detachSecondaryEvents(); 323 this.viewMode = this.o.startView; 324 this.showMode(); 325 326 if ( 327 this.o.forceParse && 328 ( 329 this.isInput && this.element.val() || 330 this.hasInput && this.element.find('input').val() 331 ) 332 ) 333 this.setValue(); 334 this._trigger('hide'); 335 }, 336 337 remove: function() { 338 this.hide(); 339 this._detachEvents(); 340 this._detachSecondaryEvents(); 341 this.picker.remove(); 342 delete this.element.data().datepicker; 343 if (!this.isInput) { 344 delete this.element.data().date; 345 } 346 }, 347 348 _utc_to_local: function(utc){ 349 return new Date(utc.getTime() + (utc.getTimezoneOffset()*60000)); 350 }, 351 _local_to_utc: function(local){ 352 return new Date(local.getTime() - (local.getTimezoneOffset()*60000)); 353 }, 354 _zero_time: function(local){ 355 return new Date(local.getFullYear(), local.getMonth(), local.getDate()); 356 }, 357 _zero_utc_time: function(utc){ 358 return new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate())); 359 }, 360 361 getDate: function() { 362 return this._utc_to_local(this.getUTCDate()); 363 }, 364 365 getUTCDate: function() { 366 return this.date; 367 }, 368 369 setDate: function(d) { 370 this.setUTCDate(this._local_to_utc(d)); 371 }, 372 373 setUTCDate: function(d) { 374 this.date = d; 375 this.setValue(); 376 }, 377 378 setValue: function() { 379 var formatted = this.getFormattedDate(); 380 if (!this.isInput) { 381 if (this.component){ 382 this.element.find('input').val(formatted).change(); 383 } 384 } else { 385 this.element.val(formatted).change(); 386 } 387 }, 388 389 getFormattedDate: function(format) { 390 if (format === undefined) 391 format = this.o.format; 392 return DPGlobal.formatDate(this.date, format, this.o.language); 393 }, 394 395 setStartDate: function(startDate){ 396 this._process_options({startDate: startDate}); 397 this.update(); 398 this.updateNavArrows(); 399 }, 400
401 setEndDate: function(endDate){ 402 this._process_options({endDate: endDate}); 403 this.update(); 404 this.updateNavArrows(); 405 }, 406 407 setDaysOfWeekDisabled: function(daysOfWeekDisabled){ 408 this._process_options({daysOfWeekDisabled: daysOfWeekDisabled}); 409 this.update(); 410 this.updateNavArrows(); 411 }, 412 413 place: function(){ 414 if(this.isInline) return; 415 var calendarWidth = this.picker.outerWidth(), 416 calendarHeight = this.picker.outerHeight(), 417 visualPadding = 10, 418 windowWidth = $window.width(), 419 windowHeight = $window.height(), 420 scrollTop = $window.scrollTop(); 421 422 var zIndex = parseInt(this.element.parents().filter(function() { 423 return $(this).css('z-index') != 'auto'; 424 }).first().css('z-index'))+10; 425 var offset = this.component ? this.component.parent().offset() : this.element.offset(); 426 var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false); 427 var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false); 428 var left = offset.left, 429 top = offset.top; 430 431 this.picker.removeClass( 432 'datepicker-orient-top datepicker-orient-bottom '+ 433 'datepicker-orient-right datepicker-orient-left' 434 ); 435 436 if (this.o.orientation.x !== 'auto') { 437 this.picker.addClass('datepicker-orient-' + this.o.orientation.x); 438 if (this.o.orientation.x === 'right') 439 left -= calendarWidth - width; 440 } 441 // auto x orientation is best-placement: if it crosses a window 442 // edge, fudge it sideways 443 else { 444 // Default to left 445 this.picker.addClass('datepicker-orient-left'); 446 if (offset.left < 0) 447 left -= offset.left - visualPadding; 448 else if (offset.left + calendarWidth > windowWidth) 449 left = windowWidth - calendarWidth - visualPadding; 450 } 451 452 // auto y orientation is best-situation: top or bottom, no fudging, 453 // decision based on which shows more of the calendar 454 var yorient = this.o.orientation.y, 455 top_overflow, bottom_overflow; 456 if (yorient === 'auto') { 457 top_overflow = -scrollTop + offset.top - calendarHeight; 458 bottom_overflow = scrollTop + windowHeight - (offset.top + height + calendarHeight); 459 if (Math.max(top_overflow, bottom_overflow) === bottom_overflow) 460 yorient = 'top'; 461 else 462 yorient = 'bottom'; 463 } 464 this.picker.addClass('datepicker-orient-' + yorient); 465 if (yorient === 'top') 466 top += height; 467 else 468 top -= calendarHeight + parseInt(this.picker.css('padding-top')); 469 470 this.picker.css({ 471 top: top, 472 left: left, 473 zIndex: zIndex 474 }); 475 }, 476 477 _allow_update: true, 478 update: function(){ 479 if (!this._allow_update) return; 480 481 var oldDate = new Date(this.date), 482 date, fromArgs = false; 483 if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) { 484 date = arguments[0]; 485 if (date instanceof Date) 486 date = this._local_to_utc(date); 487 fromArgs = true; 488 } else { 489 date = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val(); 490 delete this.element.data().date; 491 } 492 493 this.date = DPGlobal.parseDate(date, this.o.format, this.o.language); 494 495 if (fromArgs) { 496 // setting date by clicking 497 this.setValue(); 498 } else if (date) { 499 // setting date by typing 500 if (oldDate.getTime() !== this.date.getTime()) 501 this._trigger('changeDate'); 502 } else { 503 // clearing date 504 this._trigger('clearDate'); 505 } 506 507 if (this.date < this.o.startDate) { 508 this.viewDate = new Date(this.o.startDate); 509 this.date = new Date(this.o.startDate); 510 } else if (this.date > this.o.endDate) { 511 this.viewDate = new Date(this.o.endDate); 512 this.date = new Date(this.o.endDate); 513 } else { 514 this.viewDate = new Date(this.date); 515 this.date = new Date(this.date); 516 } 517 this.fill(); 518 }, 519 520 fillDow: function(){ 521 var dowCnt = this.o.weekStart, 522 html = '<tr>'; 523 if(this.o.calendarWeeks){ 524 var cell = '<th class="cw"> </th>'; 525 html += cell; 526 this.picker.find('.datepicker-days thead tr:first-child').prepend(cell); 527 } 528 while (dowCnt < this.o.weekStart + 7) { 529 html += '<th class="dow">'+dates[this.o.language].daysMin[(dowCnt++)%7]+'</th>'; 530 } 531 html += '</tr>'; 532 this.picker.find('.datepicker-days thead').append(html); 533 }, 534 535 fillMonths: function(){ 536 var html = '', 537 i = 0; 538 while (i < 12) { 539 html += '<span class="month">'+dates[this.o.language].monthsShort[i++]+'</span>'; 540 } 541 this.picker.find('.datepicker-months td').html(html); 542 }, 543 544 setRange: function(range){ 545 if (!range || !range.length) 546 delete this.range; 547 else 548 this.range = $.map(range, function(d){ return d.valueOf(); }); 549 this.fill(); 550 }, 551 552 getClassNames: function(date){ 553 var cls = [], 554 year = this.viewDate.getUTCFullYear(),
vendor: 26,491 bytes, lines 555-1382
555 month = this.viewDate.getUTCMonth(), 556 currentDate = this.date.valueOf(), 557 today = new Date(); 558 if (date.getUTCFullYear() < year || (date.getUTCFullYear() == year && date.getUTCMonth() < month)) { 559 cls.push('old'); 560 } else if (date.getUTCFullYear() > year || (date.getUTCFullYear() == year && date.getUTCMonth() > month)) { 561 cls.push('new'); 562 } 563 // Compare internal UTC date with local today, not UTC today 564 if (this.o.todayHighlight && 565 date.getUTCFullYear() == today.getFullYear() && 566 date.getUTCMonth() == today.getMonth() && 567 date.getUTCDate() == today.getDate()) { 568 cls.push('today'); 569 } 570 if (currentDate && date.valueOf() == currentDate) { 571 cls.push('active'); 572 } 573 if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate || 574 $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1) { 575 cls.push('disabled'); 576 } 577 if (this.range){ 578 if (date > this.range[0] && date < this.range[this.range.length-1]){ 579 cls.push('range'); 580 } 581 if ($.inArray(date.valueOf(), this.range) != -1){ 582 cls.push('selected'); 583 } 584 } 585 return cls; 586 }, 587 588 fill: function() { 589 var d = new Date(this.viewDate), 590 year = d.getUTCFullYear(), 591 month = d.getUTCMonth(), 592 startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity, 593 startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity, 594 endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity, 595 endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity, 596 currentDate = this.date && this.date.valueOf(), 597 tooltip; 598 this.picker.find('.datepicker-days thead th.datepicker-switch') 599 .text(dates[this.o.language].months[month]+' '+year); 600 this.picker.find('tfoot th.today') 601 .text(dates[this.o.language].today) 602 .toggle(this.o.todayBtn !== false); 603 this.picker.find('tfoot th.clear') 604 .text(dates[this.o.language].clear) 605 .toggle(this.o.clearBtn !== false); 606 this.updateNavArrows(); 607 this.fillMonths(); 608 var prevMonth = UTCDate(year, month-1, 28,0,0,0,0), 609 day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); 610 prevMonth.setUTCDate(day); 611 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7); 612 var nextMonth = new Date(prevMonth); 613 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); 614 nextMonth = nextMonth.valueOf(); 615 var html = []; 616 var clsName; 617 while(prevMonth.valueOf() < nextMonth) { 618 if (prevMonth.getUTCDay() == this.o.weekStart) { 619 html.push('<tr>'); 620 if(this.o.calendarWeeks){ 621 // ISO 8601: First week contains first thursday. 622 // ISO also states week starts on Monday, but we can be more abstract here. 623 var 624 // Start of current week: based on weekstart/current date 625 ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5), 626 // Thursday of this week 627 th = new Date(+ws + (7 + 4 - ws.getUTCDay()) % 7 * 864e5), 628 // First Thursday of year, year from thursday 629 yth = new Date(+(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay())%7*864e5), 630 // Calendar week: ms between thursdays, div ms per day, div 7 days 631 calWeek = (th - yth) / 864e5 / 7 + 1; 632 html.push('<td class="cw">'+ calWeek +'</td>'); 633 634 } 635 } 636 clsName = this.getClassNames(prevMonth); 637 clsName.push('day'); 638 639 if (this.o.beforeShowDay !== $.noop){ 640 var before = this.o.beforeShowDay(this._utc_to_local(prevMonth)); 641 if (before === undefined) 642 before = {}; 643 else if (typeof(before) === 'boolean') 644 before = {enabled: before}; 645 else if (typeof(before) === 'string') 646 before = {classes: before}; 647 if (before.enabled === false) 648 clsName.push('disabled'); 649 if (before.classes) 650 clsName = clsName.concat(before.classes.split(/\s+/)); 651 if (before.tooltip) 652 tooltip = before.tooltip; 653 } 654 655 clsName = $.unique(clsName); 656 html.push('<td class="'+clsName.join(' ')+'"' + (tooltip ? ' title="'+tooltip+'"' : '') + '>'+prevMonth.getUTCDate() + '</td>'); 657 if (prevMonth.getUTCDay() == this.o.weekEnd) { 658 html.push('</tr>'); 659 } 660 prevMonth.setUTCDate(prevMonth.getUTCDate()+1); 661 } 662 this.picker.find('.datepicker-days tbody').empty().append(html.join('')); 663 var currentYear = this.date && this.date.getUTCFullYear(); 664 665 var months = this.picker.find('.datepicker-months') 666 .find('th:eq(1)') 667 .text(year) 668 .end() 669 .find('span').removeClass('active'); 670 if (currentYear && currentYear == year) { 671 months.eq(this.date.getUTCMonth()).addClass('active'); 672 } 673 if (year < startYear || year > endYear) { 674 months.addClass('disabled'); 675 } 676 if (year == startYear) { 677 months.slice(0, startMonth).addClass('disabled'); 678 } 679 if (year == endYear) { 680 months.slice(endMonth+1).addClass('disabled'); 681 } 682 683 html = ''; 684 year = parseInt(year/10, 10) * 10; 685 var yearCont = this.picker.find('.datepicker-years') 686 .find('th:eq(1)') 687 .text(year + '-' + (year + 9)) 688 .end() 689 .find('td'); 690 year -= 1; 691 for (var i = -1; i < 11; i++) { 692 html += '<span class="year'+(i == -1 ? ' old' : i == 10 ? ' new' : '')+(currentYear == year ? ' active' : '')+(year < startYear || year > endYear ? ' disabled' : '')+'">'+year+'</span>'; 693 year += 1; 694 } 695 yearCont.html(html); 696 }, 697 698 updateNavArrows: function() { 699 if (!this._allow_update) return; 700 701 var d = new Date(this.viewDate), 702 year = d.getUTCFullYear(), 703 month = d.getUTCMonth(); 704 switch (this.viewMode) { 705 case 0: 706 if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()) { 707 this.picker.find('.prev').css({visibility: 'hidden'}); 708 } else { 709 this.picker.find('.prev').css({visibility: 'visible'}); 710 } 711 if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()) { 712 this.picker.find('.next').css({visibility: 'hidden'}); 713 } else { 714 this.picker.find('.next').css({visibility: 'visible'}); 715 } 716 break; 717 case 1: 718 case 2: 719 if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()) { 720 this.picker.find('.prev').css({visibility: 'hidden'}); 721 } else { 722 this.picker.find('.prev').css({visibility: 'visible'}); 723 } 724 if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()) { 725 this.picker.find('.next').css({visibility: 'hidden'}); 726 } else { 727 this.picker.find('.next').css({visibility: 'visible'}); 728 } 729 break; 730 } 731 }, 732 733 click: function(e) { 734 e.preventDefault(); 735 var target = $(e.target).closest('span, td, th'); 736 if (target.length == 1) { 737 switch(target[0].nodeName.toLowerCase()) { 738 case 'th': 739 switch(target[0].className) { 740 case 'datepicker-switch': 741 this.showMode(1); 742 break; 743 case 'prev': 744 case 'next': 745 var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1); 746 switch(this.viewMode){ 747 case 0: 748 this.viewDate = this.moveMonth(this.viewDate, dir); 749 this._trigger('changeMonth', this.viewDate); 750 break; 751 case 1: 752 case 2: 753 this.viewDate = this.moveYear(this.viewDate, dir); 754 if (this.viewMode === 1) 755 this._trigger('changeYear', this.viewDate); 756 break; 757 } 758 this.fill(); 759 break; 760 case 'today': 761 var date = new Date(); 762 date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); 763 764 this.showMode(-2); 765 var which = this.o.todayBtn == 'linked' ? null : 'view'; 766 this._setDate(date, which); 767 break; 768 case 'clear': 769 var element; 770 if (this.isInput) 771 element = this.element; 772 else if (this.component) 773 element = this.element.find('input'); 774 if (element) 775 element.val("").change(); 776 this._trigger('changeDate'); 777 this.update(); 778 if (this.o.autoclose) 779 this.hide(); 780 break; 781 } 782 break; 783 case 'span': 784 if (!target.is('.disabled')) { 785 this.viewDate.setUTCDate(1); 786 if (target.is('.month')) { 787 var day = 1; 788 var month = target.parent().find('span').index(target); 789 var year = this.viewDate.getUTCFullYear(); 790 this.viewDate.setUTCMonth(month); 791 this._trigger('changeMonth', this.viewDate); 792 if (this.o.minViewMode === 1) { 793 this._setDate(UTCDate(year, month, day,0,0,0,0)); 794 } 795 } else { 796 var year = parseInt(target.text(), 10)||0; 797 var day = 1; 798 var month = 0; 799 this.viewDate.setUTCFullYear(year); 800 this._trigger('changeYear', this.viewDate); 801 if (this.o.minViewMode === 2) { 802 this._setDate(UTCDate(year, month, day,0,0,0,0)); 803 } 804 } 805 this.showMode(-1); 806 this.fill(); 807 } 808 break; 809 case 'td': 810 if (target.is('.day') && !target.is('.disabled')){ 811 var day = parseInt(target.text(), 10)||1; 812 var year = this.viewDate.getUTCFullYear(), 813 month = this.viewDate.getUTCMonth(); 814 if (target.is('.old')) { 815 if (month === 0) { 816 month = 11; 817 year -= 1; 818 } else { 819 month -= 1; 820 } 821 } else if (target.is('.new')) { 822 if (month == 11) { 823 month = 0; 824 year += 1; 825 } else { 826 month += 1; 827 } 828 } 829 this._setDate(UTCDate(year, month, day,0,0,0,0)); 830 } 831 break; 832 } 833 } 834 }, 835 836 _setDate: function(date, which){ 837 if (!which || which == 'date') 838 this.date = new Date(date); 839 if (!which || which == 'view') 840 this.viewDate = new Date(date); 841 this.fill(); 842 this.setValue(); 843 this._trigger('changeDate'); 844 var element; 845 if (this.isInput) { 846 element = this.element; 847 } else if (this.component){ 848 element = this.element.find('input'); 849 } 850 if (element) { 851 element.change(); 852 } 853 if (this.o.autoclose && (!which || which == 'date')) { 854 this.hide(); 855 } 856 }, 857 858 moveMonth: function(date, dir){ 859 if (!dir) return date; 860 var new_date = new Date(date.valueOf()), 861 day = new_date.getUTCDate(), 862 month = new_date.getUTCMonth(), 863 mag = Math.abs(dir), 864 new_month, test; 865 dir = dir > 0 ? 1 : -1; 866 if (mag == 1){ 867 test = dir == -1 868 // If going back one month, make sure month is not current month 869 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02) 870 ? function(){ return new_date.getUTCMonth() == month; } 871 // If going forward one month, make sure month is as expected 872 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02) 873 : function(){ return new_date.getUTCMonth() != new_month; }; 874 new_month = month + dir; 875 new_date.setUTCMonth(new_month); 876 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 877 if (new_month < 0 || new_month > 11) 878 new_month = (new_month + 12) % 12; 879 } else { 880 // For magnitudes >1, move one month at a time... 881 for (var i=0; i<mag; i++) 882 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)... 883 new_date = this.moveMonth(new_date, dir); 884 // ...then reset the day, keeping it in the new month 885 new_month = new_date.getUTCMonth(); 886 new_date.setUTCDate(day); 887 test = function(){ return new_month != new_date.getUTCMonth(); }; 888 } 889 // Common date-resetting loop -- if date is beyond end of month, make it 890 // end of month 891 while (test()){ 892 new_date.setUTCDate(--day); 893 new_date.setUTCMonth(new_month); 894 } 895 return new_date; 896 }, 897 898 moveYear: function(date, dir){ 899 return this.moveMonth(date, dir*12); 900 }, 901 902 dateWithinRange: function(date){ 903 return date >= this.o.startDate && date <= this.o.endDate; 904 }, 905 906 keydown: function(e){ 907 if (this.picker.is(':not(:visible)')){ 908 if (e.keyCode == 27) // allow escape to hide and re-show picker 909 this.show(); 910 return; 911 } 912 var dateChanged = false, 913 dir, day, month, 914 newDate, newViewDate; 915 switch(e.keyCode){ 916 case 27: // escape 917 this.hide(); 918 e.preventDefault(); 919 break; 920 case 37: // left 921 case 39: // right 922 if (!this.o.keyboardNavigation) break; 923 dir = e.keyCode == 37 ? -1 : 1; 924 if (e.ctrlKey){ 925 newDate = this.moveYear(this.date, dir); 926 newViewDate = this.moveYear(this.viewDate, dir); 927 this._trigger('changeYear', this.viewDate); 928 } else if (e.shiftKey){ 929 newDate = this.moveMonth(this.date, dir); 930 newViewDate = this.moveMonth(this.viewDate, dir); 931 this._trigger('changeMonth', this.viewDate); 932 } else { 933 newDate = new Date(this.date); 934 newDate.setUTCDate(this.date.getUTCDate() + dir); 935 newViewDate = new Date(this.viewDate); 936 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir); 937 } 938 if (this.dateWithinRange(newDate)){ 939 this.date = newDate; 940 this.viewDate = newViewDate; 941 this.setValue(); 942 this.update(); 943 e.preventDefault(); 944 dateChanged = true; 945 } 946 break; 947 case 38: // up 948 case 40: // down 949 if (!this.o.keyboardNavigation) break; 950 dir = e.keyCode == 38 ? -1 : 1; 951 if (e.ctrlKey){ 952 newDate = this.moveYear(this.date, dir); 953 newViewDate = this.moveYear(this.viewDate, dir); 954 this._trigger('changeYear', this.viewDate); 955 } else if (e.shiftKey){ 956 newDate = this.moveMonth(this.date, dir); 957 newViewDate = this.moveMonth(this.viewDate, dir); 958 this._trigger('changeMonth', this.viewDate); 959 } else { 960 newDate = new Date(this.date); 961 newDate.setUTCDate(this.date.getUTCDate() + dir * 7); 962 newViewDate = new Date(this.viewDate); 963 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7); 964 } 965 if (this.dateWithinRange(newDate)){ 966 this.date = newDate; 967 this.viewDate = newViewDate; 968 this.setValue(); 969 this.update(); 970 e.preventDefault(); 971 dateChanged = true; 972 } 973 break; 974 case 13: // enter 975 this.hide(); 976 e.preventDefault(); 977 break; 978 case 9: // tab 979 this.hide(); 980 break; 981 } 982 if (dateChanged){ 983 this._trigger('changeDate'); 984 var element; 985 if (this.isInput) { 986 element = this.element; 987 } else if (this.component){ 988 element = this.element.find('input'); 989 } 990 if (element) { 991 element.change(); 992 } 993 } 994 }, 995 996 showMode: function(dir) { 997 if (dir) { 998 this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir)); 999 } 1000 /* 1001 vitalets: fixing bug of very special conditions: 1002 jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover. 1003 Method show() does not set display css correctly and datepicker is not shown. 1004 Changed to .css('display', 'block') solve the problem. 1005 See https://github.com/vitalets/x-editable/issues/37 1006 1007 In jquery 1.7.2+ everything works fine. 1008 */ 1009 //this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); 1010 this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block'); 1011 this.updateNavArrows(); 1012 } 1013 }; 1014 1015 var DateRangePicker = function(element, options){ 1016 this.element = $(element); 1017 this.inputs = $.map(options.inputs, function(i){ return i.jquery ? i[0] : i; }); 1018 delete options.inputs; 1019 1020 $(this.inputs) 1021 .datepicker(options) 1022 .bind('changeDate', $.proxy(this.dateUpdated, this)); 1023 1024 this.pickers = $.map(this.inputs, function(i){ return $(i).data('datepicker'); }); 1025 this.updateDates(); 1026 }; 1027 DateRangePicker.prototype = { 1028 updateDates: function(){ 1029 this.dates = $.map(this.pickers, function(i){ return i.date; }); 1030 this.updateRanges(); 1031 }, 1032 updateRanges: function(){ 1033 var range = $.map(this.dates, function(d){ return d.valueOf(); }); 1034 $.each(this.pickers, function(i, p){ 1035 p.setRange(range); 1036 }); 1037 }, 1038 dateUpdated: function(e){ 1039 var dp = $(e.target).data('datepicker'), 1040 new_date = dp.getUTCDate(), 1041 i = $.inArray(e.target, this.inputs), 1042 l = this.inputs.length; 1043 if (i == -1) return; 1044 1045 if (new_date < this.dates[i]){ 1046 // Date being moved earlier/left 1047 while (i>=0 && new_date < this.dates[i]){ 1048 this.pickers[i--].setUTCDate(new_date); 1049 } 1050 } 1051 else if (new_date > this.dates[i]){ 1052 // Date being moved later/right 1053 while (i<l && new_date > this.dates[i]){ 1054 this.pickers[i++].setUTCDate(new_date); 1055 } 1056 } 1057 this.updateDates(); 1058 }, 1059 remove: function(){ 1060 $.map(this.pickers, function(p){ p.remove(); }); 1061 delete this.element.data().datepicker; 1062 } 1063 }; 1064 1065 function opts_from_el(el, prefix){ 1066 // Derive options from element data-attrs 1067 var data = $(el).data(), 1068 out = {}, inkey, 1069 replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])'), 1070 prefix = new RegExp('^' + prefix.toLowerCase()); 1071 for (var key in data) 1072 if (prefix.test(key)){ 1073 inkey = key.replace(replace, function(_,a){ return a.toLowerCase(); }); 1074 out[inkey] = data[key]; 1075 } 1076 return out; 1077 } 1078 1079 function opts_from_locale(lang){ 1080 // Derive options from locale plugins 1081 var out = {}; 1082 // Check if "de-DE" style date is available, if not language should 1083 // fallback to 2 letter code eg "de" 1084 if (!dates[lang]) { 1085 lang = lang.split('-')[0] 1086 if (!dates[lang]) 1087 return; 1088 } 1089 var d = dates[lang]; 1090 $.each(locale_opts, function(i,k){ 1091 if (k in d) 1092 out[k] = d[k]; 1093 }); 1094 return out; 1095 } 1096 1097 var old = $.fn.datepicker; 1098 $.fn.datepicker = function ( option ) { 1099 var args = Array.apply(null, arguments); 1100 args.shift(); 1101 var internal_return, 1102 this_return; 1103 this.each(function () { 1104 var $this = $(this), 1105 data = $this.data('datepicker'), 1106 options = typeof option == 'object' && option; 1107 if (!data) { 1108 var elopts = opts_from_el(this, 'date'), 1109 // Preliminary otions 1110 xopts = $.extend({}, defaults, elopts, options), 1111 locopts = opts_from_locale(xopts.language), 1112 // Options priority: js args, data-attrs, locales, defaults 1113 opts = $.extend({}, defaults, locopts, elopts, options); 1114 if ($this.is('.input-daterange') || opts.inputs){ 1115 var ropts = { 1116 inputs: opts.inputs || $this.find('input').toArray() 1117 }; 1118 $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts)))); 1119 } 1120 else{ 1121 $this.data('datepicker', (data = new Datepicker(this, opts))); 1122 } 1123 } 1124 if (typeof option == 'string' && typeof data[option] == 'function') { 1125 internal_return = data[option].apply(data, args); 1126 if (internal_return !== undefined) 1127 return false; 1128 } 1129 }); 1130 if (internal_return !== undefined) 1131 return internal_return; 1132 else 1133 return this; 1134 }; 1135 1136 var defaults = $.fn.datepicker.defaults = { 1137 autoclose: false, 1138 beforeShowDay: $.noop, 1139 calendarWeeks: false, 1140 clearBtn: false, 1141 daysOfWeekDisabled: [], 1142 endDate: Infinity, 1143 forceParse: true, 1144 format: 'dd.mm.yyyy', 1145 keyboardNavigation: true, 1146 language: 'ru', 1147 minViewMode: 0, 1148 orientation: "auto", 1149 rtl: false, 1150 startDate: -Infinity, 1151 startView: 0, 1152 todayBtn: false, 1153 todayHighlight: false, 1154 weekStart: 1 1155 }; 1156 var locale_opts = $.fn.datepicker.locale_opts = [ 1157 'format', 1158 'rtl', 1159 'weekStart' 1160 ]; 1161 $.fn.datepicker.Constructor = Datepicker; 1162 var dates = $.fn.datepicker.dates = { 1163 en: { 1164 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], 1165 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], 1166 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], 1167 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], 1168 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], 1169 today: "Today", 1170 clear: "Clear" 1171 }, 1172 }; 1173 1174 var DPGlobal = { 1175 modes: [ 1176 { 1177 clsName: 'days', 1178 navFnc: 'Month', 1179 navStep: 1 1180 }, 1181 { 1182 clsName: 'months', 1183 navFnc: 'FullYear', 1184 navStep: 1 1185 }, 1186 { 1187 clsName: 'years', 1188 navFnc: 'FullYear', 1189 navStep: 10 1190 }], 1191 isLeapYear: function (year) { 1192 return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); 1193 }, 1194 getDaysInMonth: function (year, month) { 1195 return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; 1196 }, 1197 validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, 1198 nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g, 1199 parseFormat: function(format){ 1200 // IE treats \0 as a string end in inputs (truncating the value), 1201 // so it's a bad format delimiter, anyway 1202 var separators = format.replace(this.validParts, '\0').split('\0'), 1203 parts = format.match(this.validParts); 1204 if (!separators || !separators.length || !parts || parts.length === 0){ 1205 throw new Error("Invalid date format."); 1206 } 1207 return {separators: separators, parts: parts}; 1208 }, 1209 parseDate: function(date, format, language) { 1210 if (date instanceof Date) return date; 1211 if (typeof format === 'string') 1212 format = DPGlobal.parseFormat(format); 1213 if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) { 1214 var part_re = /([\-+]\d+)([dmwy])/, 1215 parts = date.match(/([\-+]\d+)([dmwy])/g), 1216 part, dir; 1217 date = new Date(); 1218 for (var i=0; i<parts.length; i++) { 1219 part = part_re.exec(parts[i]); 1220 dir = parseInt(part[1]); 1221 switch(part[2]){ 1222 case 'd': 1223 date.setUTCDate(date.getUTCDate() + dir); 1224 break; 1225 case 'm': 1226 date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir); 1227 break; 1228 case 'w': 1229 date.setUTCDate(date.getUTCDate() + dir * 7); 1230 break; 1231 case 'y': 1232 date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir); 1233 break; 1234 } 1235 } 1236 return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0); 1237 } 1238 var parts = date && date.match(this.nonpunctuation) || [], 1239 date = new Date(), 1240 parsed = {}, 1241 setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'], 1242 setters_map = { 1243 yyyy: function(d,v){ return d.setUTCFullYear(v); }, 1244 yy: function(d,v){ return d.setUTCFullYear(2000+v); }, 1245 m: function(d,v){ 1246 if (isNaN(d)) 1247 return d; 1248 v -= 1; 1249 while (v<0) v += 12; 1250 v %= 12; 1251 d.setUTCMonth(v); 1252 while (d.getUTCMonth() != v) 1253 d.setUTCDate(d.getUTCDate()-1); 1254 return d; 1255 }, 1256 d: function(d,v){ return d.setUTCDate(v); } 1257 }, 1258 val, filtered, part; 1259 setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m']; 1260 setters_map['dd'] = setters_map['d']; 1261 date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); 1262 var fparts = format.parts.slice(); 1263 // Remove noop parts 1264 if (parts.length != fparts.length) { 1265 fparts = $(fparts).filter(function(i,p){ 1266 return $.inArray(p, setters_order) !== -1; 1267 }).toArray(); 1268 } 1269 // Process remainder 1270 if (parts.length == fparts.length) { 1271 for (var i=0, cnt = fparts.length; i < cnt; i++) { 1272 val = parseInt(parts[i], 10); 1273 part = fparts[i]; 1274 if (isNaN(val)) { 1275 switch(part) { 1276 case 'MM': 1277 filtered = $(dates[language].months).filter(function(){ 1278 var m = this.slice(0, parts[i].length), 1279 p = parts[i].slice(0, m.length); 1280 return m == p; 1281 }); 1282 val = $.inArray(filtered[0], dates[language].months) + 1; 1283 break; 1284 case 'M': 1285 filtered = $(dates[language].monthsShort).filter(function(){ 1286 var m = this.slice(0, parts[i].length), 1287 p = parts[i].slice(0, m.length); 1288 return m == p; 1289 }); 1290 val = $.inArray(filtered[0], dates[language].monthsShort) + 1; 1291 break; 1292 } 1293 } 1294 parsed[part] = val; 1295 } 1296 for (var i=0, _date, s; i<setters_order.length; i++){ 1297 s = setters_order[i]; 1298 if (s in parsed && !isNaN(parsed[s])){ 1299 _date = new Date(date); 1300 setters_map[s](_date, parsed[s]); 1301 if (!isNaN(_date)) 1302 date = _date; 1303 } 1304 } 1305 } 1306 return date; 1307 }, 1308 formatDate: function(date, format, language){ 1309 if (typeof format === 'string') 1310 format = DPGlobal.parseFormat(format); 1311 var val = { 1312 d: date.getUTCDate(), 1313 D: dates[language].daysShort[date.getUTCDay()], 1314 DD: dates[language].days[date.getUTCDay()], 1315 m: date.getUTCMonth() + 1, 1316 M: dates[language].monthsShort[date.getUTCMonth()], 1317 MM: dates[language].months[date.getUTCMonth()], 1318 yy: date.getUTCFullYear().toString().substring(2), 1319 yyyy: date.getUTCFullYear() 1320 }; 1321 val.dd = (val.d < 10 ? '0' : '') + val.d; 1322 val.mm = (val.m < 10 ? '0' : '') + val.m; 1323 var date = [], 1324 seps = $.extend([], format.separators); 1325 for (var i=0, cnt = format.parts.length; i <= cnt; i++) { 1326 if (seps.length) 1327 date.push(seps.shift()); 1328 date.push(val[format.parts[i]]); 1329 } 1330 return date.join(''); 1331 }, 1332 headTemplate: '<thead>'+ 1333 '<tr>'+ 1334 '<th class="prev"><i class="fa fa-angle-left"></i></th>'+ 1335 '<th colspan="5" class="datepicker-switch"></th>'+ 1336 '<th class="next"><i class="fa fa-angle-right"></i></th>'+ 1337 '</tr>'+ 1338 '</thead>', 1339 contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>', 1340 footTemplate: '<tfoot><tr><th colspan="7" class="today"></th></tr><tr><th colspan="7" class="clear"></th></tr></tfoot>' 1341 }; 1342 DPGlobal.template = '<div class="datepicker">'+ 1343 '<div class="datepicker-days">'+ 1344 '<table class=" table-condensed">'+ 1345 DPGlobal.headTemplate+ 1346 '<tbody></tbody>'+ 1347 DPGlobal.footTemplate+ 1348 '</table>'+ 1349 '</div>'+ 1350 '<div class="datepicker-months">'+ 1351 '<table class="table-condensed">'+ 1352 DPGlobal.headTemplate+ 1353 DPGlobal.contTemplate+ 1354 DPGlobal.footTemplate+ 1355 '</table>'+ 1356 '</div>'+ 1357 '<div class="datepicker-years">'+ 1358 '<table class="table-condensed">'+ 1359 DPGlobal.headTemplate+ 1360 DPGlobal.contTemplate+ 1361 DPGlobal.footTemplate+ 1362 '</table>'+ 1363 '</div>'+ 1364 '</div>'; 1365 1366 $.fn.datepicker.DPGlobal = DPGlobal; 1367 1368 1369 /* DATEPICKER NO CONFLICT 1370 * =================== */ 1371 1372 $.fn.datepicker.noConflict = function(){ 1373 $.fn.datepicker = old; 1374 return this; 1375 }; 1376 1377 1378 /* DATEPICKER DATA-API 1379 * ================== */ 1380 1381 $(document).on( 1382 'focus.datepicker.data-api click.datepicker.data-api',
1383 '[data-provide="datepicker"]', 1384 function(e){ 1385 var $this = $(this); 1386 if ($this.data('datepicker')) return; 1387 e.preventDefault(); 1388 // component click requires us to explicitly show it 1389 $this.datepicker('show'); 1390 } 1391 ); 1392 $(function(){ 1393 $('[data-provide="datepicker-inline"]').datepicker(); 1394 }); 1395 1396}( 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.