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