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