1 2/* ========================================================= 3 * foundation-datepicker.js 4 * Copyright 2013 Peter Beno, [email protected], @benopeter 5 * project website http://foundation-datepicker.peterbeno.com 6 * 7 * original project: 8 * bootstrap-datepicker.js 9 * http://www.eyecon.ro/bootstrap-datepicker 10 * ========================================================= 11 * Copyright 2012 Stefan Petre 12 * Improvements by Andrew Rowls 13 * 14 * Licensed under the Apache License, Version 2.0 (the "License"); 15 * you may not use this file except in compliance with the License. 16 * You may obtain a copy of the License at 17 * 18 * http://www.apache.org/licenses/LICENSE-2.0 19 * 20 * Unless required by applicable law or agreed to in writing, software 21 * distributed under the License is distributed on an "AS IS" BASIS, 22 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 23 * See the License for the specific language governing permissions and 24 * limitations under the License. 25 * ========================================================= */ 26 27!function( $ ) { 28 29 function UTCDate(){ 30 return new Date(Date.UTC.apply(Date, arguments)); 31 } 32 function UTCToday(){ 33 var today = new Date(); 34 return UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate()); 35 } 36 37 // Picker object 38 39 var Datepicker = function(element, options) { 40 var that = this; 41 42 this.element = $(element); 43 this.closeButton = options.closeButton; 44 this.language = options.language||this.element.data('date-language')||"en"; 45 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" 46 this.language = this.language in dates ? this.language : "en"; 47 this.isRTL = dates[this.language].rtl||false; 48 this.format = DPGlobal.parseFormat(options.format||this.element.data('date-format')||dates[this.language].format||'mm/dd/yyyy'); 49 this.isInline = false; 50 this.isInput = this.element.is('input'); 51 this.component = this.element.is('.date') ? this.element.find('.prefix') : false; 52 this.hasInput = this.component && this.element.find('input').length; 53 54 55 this.onRender = options.onRender || function () {}; 56 if(this.component && this.component.length === 0) 57 this.component = false; 58 59 this._attachEvents(); 60 61 this.forceParse = true; 62 if ('forceParse' in options) { 63 this.forceParse = options.forceParse; 64 } else if ('dateForceParse' in this.element.data()) { 65 this.forceParse = this.element.data('date-force-parse'); 66 } 67 68 69 this.picker = $(DPGlobal.template) 70 .appendTo(this.isInline ? this.element : 'body') 71 .on({ 72 click: $.proxy(this.click, this), 73 mousedown: $.proxy(this.mousedown, this) 74 }); 75 if (this.closeButton){ 76 this.picker.find('a.datepicker-close').show(); 77 } 78 79 if(this.isInline) { 80 this.picker.addClass('datepicker-inline'); 81 } else { 82 this.picker.addClass('datepicker-dropdown dropdown-menu'); 83 } 84 if (this.isRTL){ 85 this.picker.addClass('datepicker-rtl'); 86 this.picker.find('.prev i, .next i') 87 .toggleClass('icon-arrow-left icon-arrow-right'); 88 } 89 $(document).on('mousedown', function (e) { 90 // Clicked outside the datepicker, hide it 91 if ($(e.target).closest('.datepicker.datepicker-inline, .datepicker.datepicker-dropdown').length === 0) { 92 that.hide(); 93 } 94 }); 95 96 this.autoclose = true; 97 if ('autoclose' in options) { 98 this.autoclose = options.autoclose; 99 } else if ('dateAutoclose' in this.element.data()) { 100 this.autoclose = this.element.data('date-autoclose'); 101 } 102 103 this.keyboardNavigation = true; 104 if ('keyboardNavigation' in options) { 105 this.keyboardNavigation = options.keyboardNavigation; 106 } else if ('dateKeyboardNavigation' in this.element.data()) { 107 this.keyboardNavigation = this.element.data('date-keyboard-navigation'); 108 } 109 110 this.viewMode = this.startViewMode = 0; 111 switch(options.startView || this.element.data('date-start-view')){ 112 case 2: 113 case 'decade': 114 this.viewMode = this.startViewMode = 2; 115 break; 116 case 1: 117 case 'year': 118 this.viewMode = this.startViewMode = 1; 119 break; 120 } 121 122 this.todayBtn = (options.todayBtn||this.element.data('date-today-btn')||false); 123 this.todayHighlight = (options.todayHighlight||this.element.data('date-today-highlight')||false); 124 125 this.calendarWeeks = false;
126 if ('calendarWeeks' in options) { 127 this.calendarWeeks = options.calendarWeeks; 128 } else if ('dateCalendarWeeks' in this.element.data()) { 129 this.calendarWeeks = this.element.data('date-calendar-weeks'); 130 } 131 if (this.calendarWeeks) 132 this.picker.find('tfoot th.today') 133 .attr('colspan', function(i, val){ 134 return parseInt(val) + 1; 135 }); 136 137 this.weekStart = ((options.weekStart||this.element.data('date-weekstart')||dates[this.language].weekStart||0) % 7); 138 this.weekEnd = ((this.weekStart + 6) % 7); 139 this.startDate = -Infinity; 140 this.endDate = Infinity; 141 this.daysOfWeekDisabled = []; 142 this.setStartDate(options.startDate||this.element.data('date-startdate')); 143 this.setEndDate(options.endDate||this.element.data('date-enddate')); 144 this.setDaysOfWeekDisabled(options.daysOfWeekDisabled||this.element.data('date-days-of-week-disabled')); 145 146 this.fillDow(); 147 this.fillMonths(); 148 this.update(); 149 this.showMode(); 150 151 if(this.isInline) { 152 this.show(); 153 } 154 }; 155 156 Datepicker.prototype = { 157 constructor: Datepicker, 158 159 _events: [], 160 _attachEvents: function(){ 161 this._detachEvents(); 162 if (this.isInput) { // single input 163 this._events = [ 164 [this.element, { 165 focus: $.proxy(this.show, this), 166 keyup: $.proxy(this.update, this), 167 keydown: $.proxy(this.keydown, this) 168 }] 169 ]; 170 } 171 else if (this.component && this.hasInput){ // component: input + button 172 this._events = [ 173 // For components that are not readonly, allow keyboard nav 174 [this.element.find('input'), { 175 focus: $.proxy(this.show, this), 176 keyup: $.proxy(this.update, this), 177 keydown: $.proxy(this.keydown, this) 178 }], 179 [this.component, { 180 click: $.proxy(this.show, this) 181 }] 182 ]; 183 } 184 else if (this.element.is('div')) { // inline datepicker 185 this.isInline = true; 186 } 187 else { 188 this._events = [ 189 [this.element, { 190 click: $.proxy(this.show, this) 191 }] 192 ]; 193 } 194 for (var i=0, el, ev; i<this._events.length; i++){ 195 el = this._events[i][0]; 196 ev = this._events[i][1]; 197 el.on(ev); 198 } 199 }, 200 _detachEvents: function(){ 201 for (var i=0, el, ev; i<this._events.length; i++){ 202 el = this._events[i][0]; 203 ev = this._events[i][1]; 204 el.off(ev); 205 } 206 this._events = []; 207 }, 208 209 show: function(e) { 210 this.picker.show(); 211 this.height = this.component ? this.component.outerHeight() : this.element.outerHeight(); 212 this.update(); 213 this.place(); 214 $(window).on('resize', $.proxy(this.place, this)); 215 if (e ) { 216 e.stopPropagation(); 217 e.preventDefault(); 218 } 219 this.element.trigger({ 220 type: 'show', 221 date: this.date 222 }); 223 }, 224 225 hide: function(e){ 226 if(this.isInline) return; 227 if (!this.picker.is(':visible')) return; 228 this.picker.hide(); 229 $(window).off('resize', this.place); 230 this.viewMode = this.startViewMode; 231 this.showMode(); 232 if (!this.isInput) { 233 $(document).off('mousedown', this.hide); 234 } 235 236 if ( 237 this.forceParse && 238 ( 239 this.isInput && this.element.val() || 240 this.hasInput && this.element.find('input').val() 241 ) 242 ) 243 this.setValue(); 244 this.element.trigger({ 245 type: 'hide', 246 date: this.date 247 }); 248 }, 249 250 remove: function() { 251 this._detachEvents(); 252 this.picker.remove(); 253 delete this.element.data().datepicker; 254 }, 255 256 getDate: function() { 257 var d = this.getUTCDate(); 258 return new Date(d.getTime() + (d.getTimezoneOffset()*60000)); 259 }, 260 261 getUTCDate: function() { 262 return this.date; 263 }, 264 265 setDate: function(d) { 266 this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000))); 267 }, 268 269 setUTCDate: function(d) { 270 this.date = d; 271 this.setValue(); 272 }, 273 274 setValue: function() { 275 var formatted = this.getFormattedDate(); 276 if (!this.isInput) { 277 if (this.component){ 278 this.element.find('input').val(formatted); 279 } 280 this.element.data('date', formatted); 281 } else { 282 this.element.val(formatted); 283 } 284 }, 285 286 getFormattedDate: function(format) { 287 if (format === undefined) 288 format = this.format; 289 return DPGlobal.formatDate(this.date, format, this.language); 290 }, 291 292 setStartDate: function(startDate){ 293 this.startDate = startDate||-Infinity; 294 if (this.startDate !== -Infinity) { 295 this.startDate = DPGlobal.parseDate(this.startDate, this.format, this.language); 296 } 297 this.update(); 298 this.updateNavArrows(); 299 }, 300
301 setEndDate: function(endDate){ 302 this.endDate = endDate||Infinity; 303 if (this.endDate !== Infinity) { 304 this.endDate = DPGlobal.parseDate(this.endDate, this.format, this.language); 305 } 306 this.update(); 307 this.updateNavArrows(); 308 }, 309 310 setDaysOfWeekDisabled: function(daysOfWeekDisabled){ 311 this.daysOfWeekDisabled = daysOfWeekDisabled||[]; 312 if (!$.isArray(this.daysOfWeekDisabled)) { 313 this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/); 314 } 315 this.daysOfWeekDisabled = $.map(this.daysOfWeekDisabled, function (d) { 316 return parseInt(d, 10); 317 }); 318 this.update(); 319 this.updateNavArrows(); 320 }, 321 322 place: function(){ 323 if(this.isInline) return; 324 var zIndex = parseInt(this.element.parents().filter(function() { 325 return $(this).css('z-index') != 'auto'; 326 }).first().css('z-index'))+10; 327 var textbox = this.component ? this.component : this.element; 328 var offset = textbox.offset(); 329 var height = textbox.outerHeight() + parseInt(textbox.css('margin-top')); 330 this.picker.css({ 331 top: offset.top + height, 332 left: offset.left, 333 zIndex: zIndex 334 }); 335 }, 336 337 update: function(){ 338 var date, fromArgs = false; 339 if(arguments && arguments.length && (typeof arguments[0] === 'string' || arguments[0] instanceof Date)) { 340 date = arguments[0]; 341 fromArgs = true; 342 } else { 343 date = this.isInput ? this.element.val() : this.element.data('date') || this.element.find('input').val(); 344 } 345 346 this.date = DPGlobal.parseDate(date, this.format, this.language); 347 348 if(fromArgs) this.setValue(); 349 350 if (this.date < this.startDate) { 351 this.viewDate = new Date(this.startDate); 352 } else if (this.date > this.endDate) { 353 this.viewDate = new Date(this.endDate); 354 } else { 355 this.viewDate = new Date(this.date); 356 } 357 this.fill(); 358 }, 359 360 fillDow: function(){ 361 var dowCnt = this.weekStart, 362 html = '<tr>'; 363 if(this.calendarWeeks){ 364 var cell = '<th class="cw"> </th>'; 365 html += cell; 366 this.picker.find('.datepicker-days thead tr:first-child').prepend(cell); 367 } 368 while (dowCnt < this.weekStart + 7) { 369 html += '<th class="dow">'+dates[this.language].daysMin[(dowCnt++)%7]+'</th>'; 370 } 371 html += '</tr>'; 372 this.picker.find('.datepicker-days thead').append(html); 373 }, 374 375 fillMonths: function(){ 376 var html = '', 377 i = 0; 378 while (i < 12) { 379 html += '<span class="month">'+dates[this.language].monthsShort[i++]+'</span>'; 380 } 381 this.picker.find('.datepicker-months td').html(html); 382 }, 383 384 fill: function() { 385 var d = new Date(this.viewDate), 386 year = d.getUTCFullYear(), 387 month = d.getUTCMonth(), 388 startYear = this.startDate !== -Infinity ? this.startDate.getUTCFullYear() : -Infinity, 389 startMonth = this.startDate !== -Infinity ? this.startDate.getUTCMonth() : -Infinity, 390 endYear = this.endDate !== Infinity ? this.endDate.getUTCFullYear() : Infinity, 391 endMonth = this.endDate !== Infinity ? this.endDate.getUTCMonth() : Infinity, 392 currentDate = this.date && this.date.valueOf(), 393 today = new Date(); 394 this.picker.find('.datepicker-days thead th.date-switch') 395 .text(dates[this.language].months[month]+' '+year); 396 this.picker.find('tfoot th.today') 397 .text(dates[this.language].today) 398 .toggle(this.todayBtn !== false); 399 this.updateNavArrows(); 400 this.fillMonths(); 401 var prevMonth = UTCDate(year, month-1, 28,0,0,0,0), 402 day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth()); 403 prevMonth.setUTCDate(day); 404 prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.weekStart + 7)%7); 405 var nextMonth = new Date(prevMonth); 406 nextMonth.setUTCDate(nextMonth.getUTCDate() + 42); 407 nextMonth = nextMonth.valueOf(); 408 var html = []; 409 var clsName; 410 while(prevMonth.valueOf() < nextMonth) { 411 if (prevMonth.getUTCDay() == this.weekStart) { 412 html.push('<tr>'); 413 if(this.calendarWeeks){ 414 // adapted from https://github.com/timrwood/moment/blob/master/moment.js#L128 415 var a = new Date(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth(), prevMonth.getUTCDate() - prevMonth.getDay() + 10 - (this.weekStart && this.weekStart%7 < 5 && 7)), 416 b = new Date(a.getFullYear(), 0, 4), 417 calWeek = ~~((a - b) / 864e5 / 7 + 1.5); 418 html.push('<td class="cw">'+ calWeek +'</td>'); 419 } 420 } 421 clsName = ' '+this.onRender(prevMonth)+' '; 422 if (prevMonth.getUTCFullYear() < year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() < month)) { 423 clsName += ' old'; 424 } else if (prevMonth.getUTCFullYear() > year || (prevMonth.getUTCFullYear() == year && prevMonth.getUTCMonth() > month)) { 425 clsName += ' new'; 426 } 427 // Compare internal UTC date with local today, not UTC today 428 if (this.todayHighlight && 429 prevMonth.getUTCFullYear() == today.getFullYear() && 430 prevMonth.getUTCMonth() == today.getMonth() && 431 prevMonth.getUTCDate() == today.getDate()) { 432 clsName += ' today'; 433 } 434 if (currentDate && prevMonth.valueOf() == currentDate) { 435 clsName += ' active'; 436 } 437 if (prevMonth.valueOf() < this.startDate || prevMonth.valueOf() > this.endDate || 438 $.inArray(prevMonth.getUTCDay(), this.daysOfWeekDisabled) !== -1) { 439 clsName += ' disabled'; 440 } 441 html.push('<td class="day'+clsName+'">'+prevMonth.getUTCDate() + '</td>'); 442 if (prevMonth.getUTCDay() == this.weekEnd) { 443 html.push('</tr>'); 444 } 445 prevMonth.setUTCDate(prevMonth.getUTCDate()+1); 446 } 447 this.picker.find('.datepicker-days tbody').empty().append(html.join('')); 448 var currentYear = this.date && this.date.getUTCFullYear(); 449 450 var months = this.picker.find('.datepicker-months') 451 .find('th:eq(1)') 452 .text(year) 453 .end() 454 .find('span').removeClass('active'); 455 if (currentYear && currentYear == year) { 456 months.eq(this.date.getUTCMonth()).addClass('active'); 457 } 458 if (year < startYear || year > endYear) { 459 months.addClass('disabled'); 460 } 461 if (year == startYear) { 462 months.slice(0, startMonth).addClass('disabled'); 463 } 464 if (year == endYear) { 465 months.slice(endMonth+1).addClass('disabled'); 466 } 467 468 html = ''; 469 year = parseInt(year/10, 10) * 10; 470 var yearCont = this.picker.find('.datepicker-years') 471 .find('th:eq(1)') 472 .text(year + '-' + (year + 9)) 473 .end() 474 .find('td'); 475 year -= 1;
476 for (var i = -1; i < 11; i++) { 477 html += '<span class="year'+(i == -1 || i == 10 ? ' old' : '')+(currentYear == year ? ' active' : '')+(year < startYear || year > endYear ? ' disabled' : '')+'">'+year+'</span>'; 478 year += 1; 479 } 480 yearCont.html(html); 481 }, 482 483 updateNavArrows: function() { 484 var d = new Date(this.viewDate), 485 year = d.getUTCFullYear(), 486 month = d.getUTCMonth(); 487 switch (this.viewMode) { 488 case 0: 489 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) { 490 //this.picker.find('.prev').css({visibility: 'hidden'}); 491 } else { 492 //this.picker.find('.prev').css({visibility: 'visible'}); 493 } 494 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) { 495 //this.picker.find('.next').css({visibility: 'hidden'}); 496 } else { 497 //this.picker.find('.next').css({visibility: 'visible'}); 498 } 499 break; 500 case 1: 501 case 2: 502 if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) { 503 this.picker.find('.prev').css({visibility: 'hidden'}); 504 } else { 505 this.picker.find('.prev').css({visibility: 'visible'}); 506 } 507 if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) { 508 this.picker.find('.next').css({visibility: 'hidden'}); 509 } else { 510 this.picker.find('.next').css({visibility: 'visible'}); 511 } 512 break; 513 } 514 }, 515 516 click: function(e) { 517 e.stopPropagation(); 518 e.preventDefault(); 519 520 if ($(e.target).hasClass('datepicker-close')){ 521 this.hide(); 522 } 523 524 var target = $(e.target).closest('span, td, th'); 525 if (target.length == 1) { 526 switch(target[0].nodeName.toLowerCase()) { 527 case 'th': 528 switch(target[0].className) { 529 case 'date-switch': 530 this.showMode(1); 531 break; 532 case 'prev': 533 case 'next': 534 var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className == 'prev' ? -1 : 1); 535 switch(this.viewMode){ 536 case 0: 537 this.viewDate = this.moveMonth(this.viewDate, dir); 538 break; 539 case 1: 540 case 2: 541 this.viewDate = this.moveYear(this.viewDate, dir); 542 break; 543 } 544 this.fill(); 545 break; 546 case 'today': 547 var date = new Date(); 548 date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); 549 550 this.showMode(-2); 551 var which = this.todayBtn == 'linked' ? null : 'view'; 552 this._setDate(date, which); 553 break; 554 } 555 break; 556 case 'span': 557 if (!target.is('.disabled')) { 558 this.viewDate.setUTCDate(1); 559 if (target.is('.month')) { 560 var month = target.parent().find('span').index(target); 561 this.viewDate.setUTCMonth(month); 562 this.element.trigger({ 563 type: 'changeMonth', 564 date: this.viewDate 565 }); 566 } else { 567 var year = parseInt(target.text(), 10)||0; 568 this.viewDate.setUTCFullYear(year); 569 this.element.trigger({ 570 type: 'changeYear', 571 date: this.viewDate 572 }); 573 } 574 this.showMode(-1); 575 this.fill(); 576 } 577 break; 578 case 'td': 579 if (target.is('.day') && !target.is('.disabled')){ 580 var day = parseInt(target.text(), 10)||1; 581 var year = this.viewDate.getUTCFullYear(), 582 month = this.viewDate.getUTCMonth(); 583 if (target.is('.old')) { 584 if (month === 0) { 585 month = 11; 586 year -= 1; 587 } else { 588 month -= 1; 589 } 590 } else if (target.is('.new')) { 591 if (month == 11) { 592 month = 0; 593 year += 1; 594 } else { 595 month += 1; 596 } 597 } 598 this._setDate(UTCDate(year, month, day,0,0,0,0)); 599 } 600 break; 601 } 602 } 603 }, 604 605 _setDate: function(date, which){ 606 if (!which || which == 'date') 607 this.date = date; 608 if (!which || which == 'view') 609 this.viewDate = date; 610 this.fill(); 611 this.setValue(); 612 this.element.trigger({ 613 type: 'changeDate', 614 date: this.date 615 }); 616 var element; 617 if (this.isInput) { 618 element = this.element; 619 } else if (this.component){ 620 element = this.element.find('input'); 621 } 622 if (element) { 623 element.change(); 624 if (this.autoclose && (!which || which == 'date')) { 625 this.hide(); 626 } 627 } 628 }, 629 630 moveMonth: function(date, dir){ 631 if (!dir) return date; 632 var new_date = new Date(date.valueOf()), 633 day = new_date.getUTCDate(),
634 month = new_date.getUTCMonth(), 635 mag = Math.abs(dir), 636 new_month, test; 637 dir = dir > 0 ? 1 : -1; 638 if (mag == 1){ 639 test = dir == -1 640 // If going back one month, make sure month is not current month 641 // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02) 642 ? function(){ return new_date.getUTCMonth() == month; } 643 // If going forward one month, make sure month is as expected 644 // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02) 645 : function(){ return new_date.getUTCMonth() != new_month; }; 646 new_month = month + dir; 647 new_date.setUTCMonth(new_month); 648 // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11 649 if (new_month < 0 || new_month > 11) 650 new_month = (new_month + 12) % 12; 651 } else { 652 // For magnitudes >1, move one month at a time... 653 for (var i=0; i<mag; i++) 654 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)... 655 new_date = this.moveMonth(new_date, dir); 656 // ...then reset the day, keeping it in the new month 657 new_month = new_date.getUTCMonth(); 658 new_date.setUTCDate(day); 659 test = function(){ return new_month != new_date.getUTCMonth(); }; 660 } 661 // Common date-resetting loop -- if date is beyond end of month, make it 662 // end of month 663 while (test()){ 664 new_date.setUTCDate(--day); 665 new_date.setUTCMonth(new_month); 666 } 667 return new_date; 668 }, 669 670 moveYear: function(date, dir){ 671 return this.moveMonth(date, dir*12); 672 }, 673 674 dateWithinRange: function(date){ 675 return date >= this.startDate && date <= this.endDate; 676 }, 677 678 keydown: function(e){ 679 if (this.picker.is(':not(:visible)')){ 680 if (e.keyCode == 27) // allow escape to hide and re-show picker 681 this.show(); 682 return; 683 } 684 var dateChanged = false, 685 dir, day, month, 686 newDate, newViewDate; 687 switch(e.keyCode){ 688 case 27: // escape 689 this.hide(); 690 e.preventDefault(); 691 break; 692 case 37: // left 693 case 39: // right 694 if (!this.keyboardNavigation) break; 695 dir = e.keyCode == 37 ? -1 : 1; 696 if (e.ctrlKey){ 697 newDate = this.moveYear(this.date, dir); 698 newViewDate = this.moveYear(this.viewDate, dir); 699 } else if (e.shiftKey){ 700 newDate = this.moveMonth(this.date, dir); 701 newViewDate = this.moveMonth(this.viewDate, dir); 702 } else { 703 newDate = new Date(this.date); 704 newDate.setUTCDate(this.date.getUTCDate() + dir); 705 newViewDate = new Date(this.viewDate); 706 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir); 707 } 708 if (this.dateWithinRange(newDate)){ 709 this.date = newDate; 710 this.viewDate = newViewDate; 711 this.setValue(); 712 this.update(); 713 e.preventDefault(); 714 dateChanged = true; 715 } 716 break; 717 case 38: // up 718 case 40: // down 719 if (!this.keyboardNavigation) break; 720 dir = e.keyCode == 38 ? -1 : 1; 721 if (e.ctrlKey){ 722 newDate = this.moveYear(this.date, dir); 723 newViewDate = this.moveYear(this.viewDate, dir); 724 } else if (e.shiftKey){ 725 newDate = this.moveMonth(this.date, dir); 726 newViewDate = this.moveMonth(this.viewDate, dir); 727 } else { 728 newDate = new Date(this.date); 729 newDate.setUTCDate(this.date.getUTCDate() + dir * 7); 730 newViewDate = new Date(this.viewDate); 731 newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7); 732 } 733 if (this.dateWithinRange(newDate)){ 734 this.date = newDate; 735 this.viewDate = newViewDate; 736 this.setValue(); 737 this.update(); 738 e.preventDefault(); 739 dateChanged = true; 740 } 741 break; 742 case 13: // enter 743 this.hide(); 744 e.preventDefault(); 745 break; 746 case 9: // tab 747 this.hide(); 748 break; 749 } 750 if (dateChanged){ 751 this.element.trigger({ 752 type: 'changeDate', 753 date: this.date 754 }); 755 var element; 756 if (this.isInput) { 757 element = this.element; 758 } else if (this.component){ 759 element = this.element.find('input'); 760 } 761 if (element) { 762 element.change(); 763 } 764 } 765 }, 766 767 showMode: function(dir) { 768 if (dir) { 769 this.viewMode = Math.max(0, Math.min(2, this.viewMode + dir)); 770 } 771 /* 772 vitalets: fixing bug of very special conditions: 773 jquery 1.7.1 + webkit + show inline datepicker in bootstrap popover. 774 Method show() does not set display css correctly and datepicker is not shown. 775 Changed to .css('display', 'block') solve the problem. 776 See https://github.com/vitalets/x-editable/issues/37 777 778 In jquery 1.7.2+ everything works fine. 779 */ 780 //this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).show(); 781 this.picker.find('>div').hide().filter('.datepicker-'+DPGlobal.modes[this.viewMode].clsName).css('display', 'block'); 782 this.updateNavArrows(); 783 } 784 }; 785 786 $.fn.fdatepicker = function ( option ) { 787 var args = Array.apply(null, arguments); 788 args.shift(); 789 return this.each(function () { 790 var $this = $(this), 791 data = $this.data('datepicker'), 792 options = typeof option == 'object' && option; 793 if (!data) { 794 $this.data('datepicker', (data = new Datepicker(this, $.extend({}, $.fn.fdatepicker.defaults,options)))); 795 } 796 if (typeof option == 'string' && typeof data[option] == 'function') { 797 data[option].apply(data, args); 798 } 799 }); 800 }; 801 802 $.fn.fdatepicker.defaults = { 803 onRender: function(date) { 804 return ''; 805 } 806 }; 807 $.fn.fdatepicker.Constructor = Datepicker; 808 var dates = $.fn.fdatepicker.dates = { 809 en: { 810 days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"], 811 daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"], 812 daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"], 813 months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
vendor: 6,224 bytes, lines 813-1005
813November", "December"], 814 monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], 815 today: "Today" 816 } 817 }; 818 819 var DPGlobal = { 820 modes: [ 821 { 822 clsName: 'days', 823 navFnc: 'Month', 824 navStep: 1 825 }, 826 { 827 clsName: 'months', 828 navFnc: 'FullYear', 829 navStep: 1 830 }, 831 { 832 clsName: 'years', 833 navFnc: 'FullYear', 834 navStep: 10 835 }], 836 isLeapYear: function (year) { 837 return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0)); 838 }, 839 getDaysInMonth: function (year, month) { 840 return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; 841 }, 842 validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g, 843 nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g, 844 parseFormat: function(format){ 845 // IE treats \0 as a string end in inputs (truncating the value), 846 // so it's a bad format delimiter, anyway 847 var separators = format.replace(this.validParts, '\0').split('\0'), 848 parts = format.match(this.validParts); 849 if (!separators || !separators.length || !parts || parts.length === 0){ 850 throw new Error("Invalid date format."); 851 } 852 return {separators: separators, parts: parts}; 853 }, 854 parseDate: function(date, format, language) { 855 if (date instanceof Date) return date; 856 if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) { 857 var part_re = /([\-+]\d+)([dmwy])/, 858 parts = date.match(/([\-+]\d+)([dmwy])/g), 859 part, dir; 860 date = new Date(); 861 for (var i=0; i<parts.length; i++) { 862 part = part_re.exec(parts[i]); 863 dir = parseInt(part[1]); 864 switch(part[2]){ 865 case 'd': 866 date.setUTCDate(date.getUTCDate() + dir); 867 break; 868 case 'm': 869 date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir); 870 break; 871 case 'w': 872 date.setUTCDate(date.getUTCDate() + dir * 7); 873 break; 874 case 'y': 875 date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir); 876 break; 877 } 878 } 879 return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0); 880 } 881 var parts = date && date.match(this.nonpunctuation) || [], 882 date = new Date(), 883 parsed = {}, 884 setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'], 885 setters_map = { 886 yyyy: function(d,v){ return d.setUTCFullYear(v); }, 887 yy: function(d,v){ return d.setUTCFullYear(2000+v); }, 888 m: function(d,v){ 889 v -= 1; 890 while (v<0) v += 12; 891 v %= 12; 892 d.setUTCMonth(v); 893 while (d.getUTCMonth() != v) 894 d.setUTCDate(d.getUTCDate()-1); 895 return d; 896 }, 897 d: function(d,v){ return d.setUTCDate(v); } 898 }, 899 val, filtered, part; 900 setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m']; 901 setters_map['dd'] = setters_map['d']; 902 date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0); 903 var fparts = format.parts.slice(); 904 // Remove noop parts 905 if (parts.length != fparts.length) { 906 fparts = $(fparts).filter(function(i,p){ 907 return $.inArray(p, setters_order) !== -1; 908 }).toArray(); 909 } 910 // Process remainder 911 if (parts.length == fparts.length) { 912 for (var i=0, cnt = fparts.length; i < cnt; i++) { 913 val = parseInt(parts[i], 10); 914 part = fparts[i]; 915 if (isNaN(val)) { 916 switch(part) { 917 case 'MM': 918 filtered = $(dates[language].months).filter(function(){ 919 var m = this.slice(0, parts[i].length), 920 p = parts[i].slice(0, m.length); 921 return m == p; 922 }); 923 val = $.inArray(filtered[0], dates[language].months) + 1; 924 break; 925 case 'M': 926 filtered = $(dates[language].monthsShort).filter(function(){ 927 var m = this.slice(0, parts[i].length), 928 p = parts[i].slice(0, m.length); 929 return m == p; 930 }); 931 val = $.inArray(filtered[0], dates[language].monthsShort) + 1; 932 break; 933 } 934 } 935 parsed[part] = val; 936 } 937 for (var i=0, s; i<setters_order.length; i++){ 938 s = setters_order[i]; 939 if (s in parsed && !isNaN(parsed[s])) 940 setters_map[s](date, parsed[s]); 941 } 942 } 943 return date; 944 }, 945 formatDate: function(date, format, language){ 946 var val = { 947 d: date.getUTCDate(), 948 D: dates[language].daysShort[date.getUTCDay()], 949 DD: dates[language].days[date.getUTCDay()], 950 m: date.getUTCMonth() + 1, 951 M: dates[language].monthsShort[date.getUTCMonth()], 952 MM: dates[language].months[date.getUTCMonth()], 953 yy: date.getUTCFullYear().toString().substring(2), 954 yyyy: date.getUTCFullYear() 955 }; 956 val.dd = (val.d < 10 ? '0' : '') + val.d; 957 val.mm = (val.m < 10 ? '0' : '') + val.m; 958 var date = [], 959 seps = $.extend([], format.separators); 960 for (var i=0, cnt = format.parts.length; i < cnt; i++) { 961 if (seps.length) 962 date.push(seps.shift()); 963 date.push(val[format.parts[i]]); 964 } 965 return date.join(''); 966 }, 967 headTemplate: '<thead>'+ 968 '<tr>'+ 969 '<th class="prev"><i class="fa fa-chevron-left"/></th>'+ 970 '<th colspan="5" class="date-switch"></th>'+ 971 '<th class="next"><i class="fa fa-chevron-right"/></th>'+ 972 '</tr>'+ 973 '</thead>', 974 contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>', 975 footTemplate: '<tfoot><tr><th colspan="7" class="today"></th></tr></tfoot>' 976 }; 977 DPGlobal.template = '<div class="datepicker">'+ 978 979 '<div class="datepicker-days">'+ 980 '<table class=" table-condensed">'+ 981 DPGlobal.headTemplate+ 982 '<tbody></tbody>'+ 983 DPGlobal.footTemplate+ 984 '</table>'+ 985 '</div>'+ 986 '<div class="datepicker-months">'+ 987 '<table class="table-condensed">'+ 988 DPGlobal.headTemplate+ 989 DPGlobal.contTemplate+ 990 DPGlobal.footTemplate+ 991 '</table>'+ 992 '</div>'+ 993 '<div class="datepicker-years">'+ 994 '<table class="table-condensed">'+ 995 DPGlobal.headTemplate+ 996 DPGlobal.contTemplate+ 997 DPGlobal.footTemplate+ 998 '</table>'+ 999 '</div>'+ 1000 '<a class="button datepicker-close small alert right" style="width:auto;"><i class="icon-remove"></i></a>'+ 1001 '</div>'; 1002 1003 $.fn.fdatepicker.DPGlobal = DPGlobal; 1004 1005}( 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.