vendor: 7,831 bytes, lines 1-249
1/*! 2 * Pikaday 3 * 4 * Copyright é 2014 David Bushell | BSD & MIT license | https://github.com/Pikaday/Pikaday 5 */ 6 7(function (root, factory) 8{ 9 'use strict'; 10 11 var moment; 12 if (typeof exports === 'object') { 13 // CommonJS module 14 // Load moment.js as an optional dependency 15 try { moment = require('moment'); } catch { /* Silently fail */ } 16 module.exports = factory(moment); 17 } else if (typeof define === 'function' && define.amd) { 18 // AMD. Register as an anonymous module. 19 define(function (req) 20 { 21 // Load moment.js as an optional dependency 22 var id = 'moment'; 23 try { moment = req(id); } catch { /* Silently fail */ } 24 return factory(moment); 25 }); 26 } else { 27 root.Pikaday = factory(root.moment); 28 } 29}(this, function (moment) 30{ 31 'use strict'; 32 33 /** 34 * feature detection and helper functions 35 */ 36 var hasMoment = typeof moment === 'function', 37 38 hasEventListeners = !!window.addEventListener, 39 40 document = window.document, 41 42 sto = window.setTimeout, 43 44 addEvent = function(el, e, callback, capture) 45 { 46 if (hasEventListeners) { 47 el.addEventListener(e, callback, !!capture); 48 } else { 49 el.attachEvent('on' + e, callback); 50 } 51 }, 52 53 removeEvent = function(el, e, callback, capture) 54 { 55 if (hasEventListeners) { 56 el.removeEventListener(e, callback, !!capture); 57 } else { 58 el.detachEvent('on' + e, callback); 59 } 60 }, 61 62 trim = function(str) 63 { 64 return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g,''); 65 }, 66 67 hasClass = function(el, cn) 68 { 69 return (' ' + el.className + ' ').indexOf(' ' + cn + ' ') !== -1; 70 }, 71 72 addClass = function(el, cn) 73 { 74 if (!hasClass(el, cn)) { 75 el.className = (el.className === '') ? cn : el.className + ' ' + cn; 76 } 77 }, 78 79 removeClass = function(el, cn) 80 { 81 el.className = trim((' ' + el.className + ' ').replace(' ' + cn + ' ', ' ')); 82 }, 83 84 isArray = function(obj) 85 { 86 return (/Array/).test(Object.prototype.toString.call(obj)); 87 }, 88 89 isDate = function(obj) 90 { 91 return (/Date/).test(Object.prototype.toString.call(obj)) && !isNaN(obj.getTime()); 92 }, 93 94 isWeekend = function(date) 95 { 96 var day = date.getDay(); 97 return day === 0 || day === 6; 98 }, 99 100 isLeapYear = function(year) 101 { 102 // solution by Matti Virkkunen: http://stackoverflow.com/a/4881951 103 return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; 104 }, 105 106 getDaysInMonth = function(year, month) 107 { 108 return [31, isLeapYear(year) ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month]; 109 }, 110 111 setToStartOfDay = function(date) 112 { 113 if (isDate(date)) date.setHours(0,0,0,0); 114 }, 115 116 compareDates = function(a,b) 117 { 118 // weak date comparison (use setToStartOfDay(date) to ensure correct result) 119 return a.getTime() === b.getTime(); 120 }, 121 122 extend = function(to, from, overwrite) 123 { 124 var prop, hasProp; 125 for (prop in from) { 126 hasProp = to[prop] !== undefined; 127 if (hasProp && typeof from[prop] === 'object' && from[prop] !== null && from[prop].nodeName === undefined) { 128 if (isDate(from[prop])) { 129 if (overwrite) { 130 to[prop] = new Date(from[prop].getTime()); 131 } 132 } 133 else if (isArray(from[prop])) { 134 if (overwrite) { 135 to[prop] = from[prop].slice(0); 136 } 137 } else { 138 to[prop] = extend({}, from[prop], overwrite); 139 } 140 } else if (overwrite || !hasProp) { 141 to[prop] = from[prop]; 142 } 143 } 144 return to; 145 }, 146 147 fireEvent = function(el, eventName, data) 148 { 149 var ev; 150 151 if (document.createEvent) { 152 ev = document.createEvent('HTMLEvents'); 153 ev.initEvent(eventName, true, false); 154 ev = extend(ev, data); 155 el.dispatchEvent(ev); 156 } else if (document.createEventObject) { 157 ev = document.createEventObject(); 158 ev = extend(ev, data); 159 el.fireEvent('on' + eventName, ev); 160 } 161 }, 162 163 adjustCalendar = function(calendar) { 164 if (calendar.month < 0) { 165 calendar.year -= Math.ceil(Math.abs(calendar.month)/12); 166 calendar.month += 12; 167 } 168 if (calendar.month > 11) { 169 calendar.year += Math.floor(Math.abs(calendar.month)/12); 170 calendar.month -= 12; 171 } 172 return calendar; 173 }, 174 175 /** 176 * defaults and localisation 177 */ 178 defaults = { 179 180 // bind the picker to a form field 181 field: null, 182 183 // automatically show/hide the picker on `field` focus (default `true` if `field` is set) 184 bound: undefined, 185 186 // data-attribute on the input field with an aria assistance tekst (only applied when `bound` is set) 187 ariaLabel: 'Use the arrow keys to pick a date', 188 189 // position of the datepicker, relative to the field (default to bottom & left) 190 // ('bottom' & 'left' keywords are not used, 'top' & 'right' are modifier on the bottom/left position) 191 position: 'bottom left', 192 193 // automatically fit in the viewport even if it means repositioning from the position option 194 reposition: true, 195 196 // the default output format for `.toString()` and `field` value 197 format: 'YYYY-MM-DD', 198 199 // the toString function which gets passed a current date object and format 200 // and returns a string 201 toString: null, 202 203 // used to create date object from current input string 204 parse: null, 205 206 // the initial date to view when first opened 207 defaultDate: null, 208 209 // make the `defaultDate` the initial selected value 210 setDefaultDate: false, 211 212 // first day of week (0: Sunday, 1: Monday etc) 213 firstDay: 0, 214 215 // the default flag for moment's strict date parsing 216 formatStrict: false, 217 218 // the minimum/earliest date that can be selected 219 minDate: null, 220 // the maximum/latest date that can be selected 221 maxDate: null, 222 223 // number of years either side, or array of upper/lower range 224 yearRange: 10, 225 226 // show week numbers at head of row 227 showWeekNumber: false, 228 229 // Week picker mode 230 pickWholeWeek: false, 231 232 // used internally (don't config outside) 233 minYear: 0, 234 maxYear: 9999, 235 minMonth: undefined, 236 maxMonth: undefined, 237 238 startRange: null, 239 endRange: null, 240 241 isRTL: false, 242 243 // Additional text to append to the year in the calendar title 244 yearSuffix: '', 245 246 // Render the month after year in the calendar title 247 showMonthAfterYear: false, 248 249 // Render days of the calendar grid that fall in the next or previous month
vendor: 12,631 bytes, lines 250-593
250 showDaysInNextAndPreviousMonths: false, 251 252 // Allows user to select days that fall in the next or previous month 253 enableSelectionDaysInNextAndPreviousMonths: false, 254 255 // how many months are visible 256 numberOfMonths: 1, 257 258 // when numberOfMonths is used, this will help you to choose where the main calendar will be (default `left`, can be set to `right`) 259 // only used for the first display or when a selected date is not visible 260 mainCalendar: 'left', 261 262 // Specify a DOM element to render the calendar in 263 container: undefined, 264 265 // Blur field when date is selected 266 blurFieldOnSelect : true, 267 268 // internationalization 269 i18n: { 270 previousMonth : 'Previous Month', 271 nextMonth : 'Next Month', 272 months : ['January','February','March','April','May','June','July','August','September','October','November','December'], 273 weekdays : ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'], 274 weekdaysShort : ['Sun','Mon','Tue','Wed','Thu','Fri','Sat'] 275 }, 276 277 // Theme Classname 278 theme: null, 279 280 // events array 281 events: [], 282 283 // callback function 284 onSelect: null, 285 onOpen: null, 286 onClose: null, 287 onDraw: null, 288 289 // Enable keyboard input 290 keyboardInput: true 291 }, 292 293 294 /** 295 * templating functions to abstract HTML rendering 296 */ 297 renderDayName = function(opts, day, abbr) 298 { 299 day += opts.firstDay; 300 while (day >= 7) { 301 day -= 7; 302 } 303 return abbr ? opts.i18n.weekdaysShort[day] : opts.i18n.weekdays[day]; 304 }, 305 306 renderDay = function(opts) 307 { 308 var arr = []; 309 var ariaSelected = 'false'; 310 if (opts.isEmpty) { 311 if (opts.showDaysInNextAndPreviousMonths) { 312 arr.push('is-outside-current-month'); 313 314 if(!opts.enableSelectionDaysInNextAndPreviousMonths) { 315 arr.push('is-selection-disabled'); 316 } 317 318 } else { 319 return '<td class="is-empty"></td>'; 320 } 321 } 322 if (opts.isDisabled) { 323 arr.push('is-disabled'); 324 } 325 if (opts.isToday) { 326 arr.push('is-today'); 327 } 328 if (opts.isSelected) { 329 arr.push('is-selected'); 330 ariaSelected = 'true'; 331 } 332 if (opts.hasEvent) { 333 arr.push('has-event'); 334 } 335 if (opts.isInRange) { 336 arr.push('is-inrange'); 337 } 338 if (opts.isStartRange) { 339 arr.push('is-startrange'); 340 } 341 if (opts.isEndRange) { 342 arr.push('is-endrange'); 343 } 344 return '<td data-day="' + opts.day + '" class="' + arr.join(' ') + '" aria-selected="' + ariaSelected + '">' + 345 '<button class="pika-button pika-day" type="button" ' + 346 'data-pika-year="' + opts.year + '" data-pika-month="' + opts.month + '" data-pika-day="' + opts.day + '">' + 347 opts.day + 348 '</button>' + 349 '</td>'; 350 }, 351 352 renderWeek = function (d, m, y) { 353 // Lifted from http://javascript.about.com/library/blweekyear.htm, lightly modified. 354 var onejan = new Date(y, 0, 1), 355 weekNum = Math.ceil((((new Date(y, m, d) - onejan) / 86400000) + onejan.getDay()+1)/7); 356 return '<td class="pika-week">' + weekNum + '</td>'; 357 }, 358 359 renderRow = function(days, isRTL, pickWholeWeek, isRowSelected) 360 { 361 return '<tr class="pika-row' + (pickWholeWeek ? ' pick-whole-week' : '') + (isRowSelected ? ' is-selected' : '') + '">' + (isRTL ? days.reverse() : days).join('') + '</tr>'; 362 }, 363 364 renderBody = function(rows) 365 { 366 return '<tbody>' + rows.join('') + '</tbody>'; 367 }, 368 369 renderHead = function(opts) 370 { 371 var i, arr = []; 372 if (opts.showWeekNumber) { 373 arr.push('<th></th>'); 374 } 375 for (i = 0; i < 7; i++) { 376 arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>'); 377 } 378 return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>'; 379 }, 380 381 renderTitle = function(instance, c, year, month, refYear, randId) 382 { 383 var i, j, arr, 384 opts = instance._o, 385 isMinYear = year === opts.minYear, 386 isMaxYear = year === opts.maxYear, 387 html = '<div id="' + randId + '" class="pika-title" role="heading" aria-live="assertive">', 388 monthHtml, 389 yearHtml, 390 prev = true, 391 next = true; 392 393 for (arr = [], i = 0; i < 12; i++) { 394 arr.push('<option value="' + (year === refYear ? i - c : 12 + i - c) + '"' + 395 (i === month ? ' selected="selected"': '') + 396 ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? 'disabled="disabled"' : '') + '>' + 397 opts.i18n.months[i] + '</option>'); 398 } 399 400 monthHtml = '<div class="pika-label">' + opts.i18n.months[month] + '<select class="pika-select pika-select-month" tabindex="-1">' + arr.join('') + '</select></div>'; 401 402 if (isArray(opts.yearRange)) { 403 i = opts.yearRange[0]; 404 j = opts.yearRange[1] + 1; 405 } else { 406 i = year - opts.yearRange; 407 j = 1 + year + opts.yearRange; 408 } 409 410 for (arr = []; i < j && i <= opts.maxYear; i++) { 411 if (i >= opts.minYear) { 412 arr.push('<option value="' + i + '"' + (i === year ? ' selected="selected"': '') + '>' + (i) + '</option>'); 413 } 414 } 415 yearHtml = '<div class="pika-label">' + year + opts.yearSuffix + '<select class="pika-select pika-select-year" tabindex="-1">' + arr.join('') + '</select></div>'; 416 417 if (opts.showMonthAfterYear) { 418 html += yearHtml + monthHtml; 419 } else { 420 html += monthHtml + yearHtml; 421 } 422 423 if (isMinYear && (month === 0 || opts.minMonth >= month)) { 424 prev = false; 425 } 426 427 if (isMaxYear && (month === 11 || opts.maxMonth <= month)) { 428 next = false; 429 } 430 431 if (c === 0) { 432 html += '<button class="pika-prev' + (prev ? '' : ' is-disabled') + '" type="button">' + opts.i18n.previousMonth + '</button>'; 433 } 434 if (c === (instance._o.numberOfMonths - 1) ) { 435 html += '<button class="pika-next' + (next ? '' : ' is-disabled') + '" type="button">' + opts.i18n.nextMonth + '</button>'; 436 } 437 438 return html += '</div>'; 439 }, 440 441 renderTable = function(opts, data, randId) 442 { 443 return '<table cellpadding="0" cellspacing="0" class="pika-table" role="grid" aria-labelledby="' + randId + '">' + renderHead(opts) + renderBody(data) + '</table>'; 444 }, 445 446 447 /** 448 * Pikaday constructor 449 */ 450 Pikaday = function(options) 451 { 452 var self = this, 453 opts = self.config(options); 454 455 self._onMouseDown = function(e) 456 { 457 if (!self._v) { 458 return; 459 } 460 e = e || window.event; 461 var target = e.target || e.srcElement; 462 if (!target) { 463 return; 464 } 465 466 if (!hasClass(target, 'is-disabled')) { 467 if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty') && !hasClass(target.parentNode, 'is-disabled')) { 468 self.setDate(new Date(target.getAttribute('data-pika-year'), target.getAttribute('data-pika-month'), target.getAttribute('data-pika-day'))); 469 if (opts.bound) { 470 sto(function() { 471 self.hide(); 472 if (opts.blurFieldOnSelect && opts.field) { 473 opts.field.blur(); 474 } 475 }, 100); 476 } 477 } 478 else if (hasClass(target, 'pika-prev')) { 479 self.prevMonth(); 480 } 481 else if (hasClass(target, 'pika-next')) { 482 self.nextMonth(); 483 } 484 } 485 if (!hasClass(target, 'pika-select')) { 486 // if this is touch event prevent mouse events emulation 487 if (e.preventDefault) { 488 e.preventDefault(); 489 } else { 490 e.returnValue = false; 491 return false; 492 } 493 } else { 494 self._c = true; 495 } 496 }; 497 498 self._onChange = function(e) 499 { 500 e = e || window.event; 501 var target = e.target || e.srcElement; 502 if (!target) { 503 return; 504 } 505 if (hasClass(target, 'pika-select-month')) { 506 self.gotoMonth(target.value); 507 } 508 else if (hasClass(target, 'pika-select-year')) { 509 self.gotoYear(target.value); 510 } 511 }; 512 513 self._onKeyChange = function(e) 514 { 515 e = e || window.event; 516 517 if (self.isVisible()) { 518 519 switch(e.keyCode){ 520 case 13: 521 case 27: 522 if (opts.field) { 523 opts.field.blur(); 524 } 525 break; 526 case 37: 527 e.preventDefault(); 528 self.adjustDate('subtract', 1); 529 break; 530 case 38: 531 self.adjustDate('subtract', 7); 532 break; 533 case 39: 534 self.adjustDate('add', 1); 535 break; 536 case 40: 537 self.adjustDate('add', 7); 538 break; 539 } 540 } 541 }; 542 543 self._onInputChange = function(e) 544 { 545 var date; 546 547 if (e.firedBy === self) { 548 return; 549 } 550 if (opts.parse) { 551 date = opts.parse(opts.field.value, opts.format); 552 } else if (hasMoment) { 553 date = moment(opts.field.value, opts.format, opts.formatStrict); 554 date = (date && date.isValid()) ? date.toDate() : null; 555 } 556 else { 557 date = new Date(Date.parse(opts.field.value)); 558 } 559 if (isDate(date)) { 560 self.setDate(date); 561 } 562 if (!self._v) { 563 self.show(); 564 } 565 }; 566 567 self._onInputFocus = function() 568 { 569 self.show(); 570 }; 571 572 self._onInputClick = function() 573 { 574 self.show(); 575 }; 576 577 self._onInputBlur = function() 578 { 579 // IE allows pika div to gain focus; catch blur the input field 580 var pEl = document.activeElement; 581 do { 582 if (hasClass(pEl, 'pika-single')) { 583 return; 584 } 585 } 586 while ((pEl = pEl.parentNode)); 587 588 if (!self._c) { 589 self._b = sto(function() { 590 self.hide(); 591 }, 50); 592 } 593 self._c = false;
vendor: 4,172 bytes, lines 594-714
594 }; 595 596 self._onClick = function(e) 597 { 598 e = e || window.event; 599 var target = e.target || e.srcElement, 600 pEl = target; 601 if (!target) { 602 return; 603 } 604 if (!hasEventListeners && hasClass(target, 'pika-select')) { 605 if (!target.onchange) { 606 target.setAttribute('onchange', 'return;'); 607 addEvent(target, 'change', self._onChange); 608 } 609 } 610 do { 611 if (hasClass(pEl, 'pika-single') || pEl === opts.trigger) { 612 return; 613 } 614 } 615 while ((pEl = pEl.parentNode)); 616 if (self._v && target !== opts.trigger && pEl !== opts.trigger) { 617 self.hide(); 618 } 619 }; 620 621 self.el = document.createElement('div'); 622 self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '') + (opts.theme ? ' ' + opts.theme : ''); 623 624 addEvent(self.el, 'mousedown', self._onMouseDown, true); 625 addEvent(self.el, 'touchend', self._onMouseDown, true); 626 addEvent(self.el, 'change', self._onChange); 627 628 if (opts.keyboardInput) { 629 addEvent(document, 'keydown', self._onKeyChange); 630 } 631 632 if (opts.field) { 633 if (opts.container) { 634 opts.container.appendChild(self.el); 635 } else if (opts.bound) { 636 document.body.appendChild(self.el); 637 } else { 638 opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling); 639 } 640 addEvent(opts.field, 'change', self._onInputChange); 641 642 if (!opts.defaultDate) { 643 if (hasMoment && opts.field.value) { 644 opts.defaultDate = moment(opts.field.value, opts.format).toDate(); 645 } else { 646 opts.defaultDate = new Date(Date.parse(opts.field.value)); 647 } 648 opts.setDefaultDate = true; 649 } 650 } 651 652 var defDate = opts.defaultDate; 653 654 if (isDate(defDate)) { 655 if (opts.setDefaultDate) { 656 self.setDate(defDate, true); 657 } else { 658 self.gotoDate(defDate); 659 } 660 } else { 661 self.gotoDate(new Date()); 662 } 663 664 if (opts.bound) { 665 this.hide(); 666 self.el.className += ' is-bound'; 667 addEvent(opts.trigger, 'click', self._onInputClick); 668 addEvent(opts.trigger, 'focus', self._onInputFocus); 669 addEvent(opts.trigger, 'blur', self._onInputBlur); 670 } else { 671 this.show(); 672 } 673 }; 674 675 676 /** 677 * public Pikaday API 678 */ 679 Pikaday.prototype = { 680 681 682 /** 683 * configure functionality 684 */ 685 config: function(options) 686 { 687 if (!this._o) { 688 this._o = extend({}, defaults, true); 689 } 690 691 var opts = extend(this._o, options, true); 692 693 opts.isRTL = !!opts.isRTL; 694 695 opts.field = (opts.field && opts.field.nodeName) ? opts.field : null; 696 697 opts.theme = (typeof opts.theme) === 'string' && opts.theme ? opts.theme : null; 698 699 opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field); 700 701 opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field; 702 703 opts.disableWeekends = !!opts.disableWeekends; 704 705 opts.disableDayFn = (typeof opts.disableDayFn) === 'function' ? opts.disableDayFn : null; 706 707 var nom = parseInt(opts.numberOfMonths, 10) || 1; 708 opts.numberOfMonths = nom > 4 ? 4 : nom; 709 710 if (!isDate(opts.minDate)) { 711 opts.minDate = false; 712 } 713 if (!isDate(opts.maxDate)) { 714 opts.maxDate = false;
vendor: 18,533 bytes, lines 715-1257
715 } 716 if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) { 717 opts.maxDate = opts.minDate = false; 718 } 719 if (opts.minDate) { 720 this.setMinDate(opts.minDate); 721 } 722 if (opts.maxDate) { 723 this.setMaxDate(opts.maxDate); 724 } 725 726 if (isArray(opts.yearRange)) { 727 var fallback = new Date().getFullYear() - 10; 728 opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback; 729 opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback; 730 } else { 731 opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange; 732 if (opts.yearRange > 100) { 733 opts.yearRange = 100; 734 } 735 } 736 737 return opts; 738 }, 739 740 /** 741 * return a formatted string of the current selection (using Moment.js if available) 742 */ 743 toString: function(format) 744 { 745 format = format || this._o.format; 746 if (!isDate(this._d)) { 747 return ''; 748 } 749 if (this._o.toString) { 750 return this._o.toString(this._d, format); 751 } 752 if (hasMoment) { 753 return moment(this._d).format(format); 754 } 755 return this._d.toDateString(); 756 }, 757 758 /** 759 * return a Moment.js object of the current selection (if available) 760 */ 761 getMoment: function() 762 { 763 return hasMoment ? moment(this._d) : null; 764 }, 765 766 /** 767 * set the current selection from a Moment.js object (if available) 768 */ 769 setMoment: function(date, preventOnSelect) 770 { 771 if (hasMoment && moment.isMoment(date)) { 772 this.setDate(date.toDate(), preventOnSelect); 773 } 774 }, 775 776 /** 777 * return a Date object of the current selection 778 */ 779 getDate: function() 780 { 781 return isDate(this._d) ? new Date(this._d.getTime()) : null; 782 }, 783 784 /** 785 * set the current selection 786 */ 787 setDate: function(date, preventOnSelect) 788 { 789 if (!date) { 790 this._d = null; 791 792 if (this._o.field) { 793 this._o.field.value = ''; 794 fireEvent(this._o.field, 'change', { firedBy: this }); 795 } 796 797 return this.draw(); 798 } 799 if (typeof date === 'string') { 800 date = new Date(Date.parse(date)); 801 } 802 if (!isDate(date)) { 803 return; 804 } 805 806 var min = this._o.minDate, 807 max = this._o.maxDate; 808 809 if (isDate(min) && date < min) { 810 date = min; 811 } else if (isDate(max) && date > max) { 812 date = max; 813 } 814 815 this._d = new Date(date.getTime()); 816 setToStartOfDay(this._d); 817 this.gotoDate(this._d); 818 819 if (this._o.field) { 820 this._o.field.value = this.toString(); 821 fireEvent(this._o.field, 'change', { firedBy: this }); 822 } 823 if (!preventOnSelect && typeof this._o.onSelect === 'function') { 824 this._o.onSelect.call(this, this.getDate()); 825 } 826 }, 827 828 /** 829 * change view to a specific date 830 */ 831 gotoDate: function(date) 832 { 833 var newCalendar = true; 834 835 if (!isDate(date)) { 836 return; 837 } 838 839 if (this.calendars) { 840 var firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1), 841 lastVisibleDate = new Date(this.calendars[this.calendars.length-1].year, this.calendars[this.calendars.length-1].month, 1), 842 visibleDate = date.getTime(); 843 // get the end of the month 844 lastVisibleDate.setMonth(lastVisibleDate.getMonth()+1); 845 lastVisibleDate.setDate(lastVisibleDate.getDate()-1); 846 newCalendar = (visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate); 847 } 848 849 if (newCalendar) { 850 this.calendars = [{ 851 month: date.getMonth(), 852 year: date.getFullYear() 853 }]; 854 if (this._o.mainCalendar === 'right') { 855 this.calendars[0].month += 1 - this._o.numberOfMonths; 856 } 857 } 858 859 this.adjustCalendars(); 860 }, 861 862 adjustDate: function(sign, days) { 863 864 var day = this.getDate() || new Date(); 865 var difference = parseInt(days)*24*60*60*1000; 866 867 var newDay; 868 869 if (sign === 'add') { 870 newDay = new Date(day.valueOf() + difference); 871 } else if (sign === 'subtract') { 872 newDay = new Date(day.valueOf() - difference); 873 } 874 875 this.setDate(newDay); 876 }, 877 878 adjustCalendars: function() { 879 this.calendars[0] = adjustCalendar(this.calendars[0]); 880 for (var c = 1; c < this._o.numberOfMonths; c++) { 881 this.calendars[c] = adjustCalendar({ 882 month: this.calendars[0].month + c, 883 year: this.calendars[0].year 884 }); 885 } 886 this.draw(); 887 }, 888 889 gotoToday: function() 890 { 891 this.gotoDate(new Date()); 892 }, 893 894 /** 895 * change view to a specific month (zero-index, e.g. 0: January) 896 */ 897 gotoMonth: function(month) 898 { 899 if (!isNaN(month)) { 900 this.calendars[0].month = parseInt(month, 10); 901 this.adjustCalendars(); 902 } 903 }, 904 905 nextMonth: function() 906 { 907 this.calendars[0].month++; 908 this.adjustCalendars(); 909 }, 910 911 prevMonth: function() 912 { 913 this.calendars[0].month--; 914 this.adjustCalendars(); 915 }, 916 917 /** 918 * change view to a specific full year (e.g. "2012") 919 */ 920 gotoYear: function(year) 921 { 922 if (!isNaN(year)) { 923 this.calendars[0].year = parseInt(year, 10); 924 this.adjustCalendars(); 925 } 926 }, 927 928 /** 929 * change the minDate 930 */ 931 setMinDate: function(value) 932 { 933 if(value instanceof Date) { 934 setToStartOfDay(value); 935 this._o.minDate = value; 936 this._o.minYear = value.getFullYear(); 937 this._o.minMonth = value.getMonth(); 938 } else { 939 this._o.minDate = defaults.minDate; 940 this._o.minYear = defaults.minYear; 941 this._o.minMonth = defaults.minMonth; 942 this._o.startRange = defaults.startRange; 943 } 944 945 this.draw(); 946 }, 947 948 /** 949 * change the maxDate 950 */ 951 setMaxDate: function(value) 952 { 953 if(value instanceof Date) { 954 setToStartOfDay(value); 955 this._o.maxDate = value; 956 this._o.maxYear = value.getFullYear(); 957 this._o.maxMonth = value.getMonth(); 958 } else { 959 this._o.maxDate = defaults.maxDate; 960 this._o.maxYear = defaults.maxYear; 961 this._o.maxMonth = defaults.maxMonth; 962 this._o.endRange = defaults.endRange; 963 } 964 965 this.draw(); 966 }, 967 968 setStartRange: function(value) 969 { 970 this._o.startRange = value; 971 }, 972 973 setEndRange: function(value) 974 { 975 this._o.endRange = value; 976 }, 977 978 /** 979 * refresh the HTML 980 */ 981 draw: function(force) 982 { 983 if (!this._v && !force) { 984 return; 985 } 986 var opts = this._o, 987 minYear = opts.minYear, 988 maxYear = opts.maxYear, 989 minMonth = opts.minMonth, 990 maxMonth = opts.maxMonth, 991 html = '', 992 randId; 993 994 if (this._y <= minYear) { 995 this._y = minYear; 996 if (!isNaN(minMonth) && this._m < minMonth) { 997 this._m = minMonth; 998 } 999 } 1000 if (this._y >= maxYear) { 1001 this._y = maxYear; 1002 if (!isNaN(maxMonth) && this._m > maxMonth) { 1003 this._m = maxMonth; 1004 } 1005 } 1006 1007 randId = 'pika-title-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2); 1008 1009 for (var c = 0; c < opts.numberOfMonths; c++) { 1010 html += '<div class="pika-lendar">' + renderTitle(this, c, this.calendars[c].year, this.calendars[c].month, this.calendars[0].year, randId) + this.render(this.calendars[c].year, this.calendars[c].month, randId) + '</div>'; 1011 } 1012 1013 this.el.innerHTML = html; 1014 1015 if (opts.bound) { 1016 if(opts.field.type !== 'hidden') { 1017 sto(function() { 1018 opts.trigger.focus(); 1019 }, 1); 1020 } 1021 } 1022 1023 if (typeof this._o.onDraw === 'function') { 1024 this._o.onDraw(this); 1025 } 1026 1027 if (opts.bound) { 1028 // let the screen reader user know to use arrow keys 1029 opts.field.setAttribute('aria-label', opts.ariaLabel); 1030 } 1031 }, 1032 1033 adjustPosition: function() 1034 { 1035 var field, pEl, width, height, viewportWidth, viewportHeight, scrollTop, left, top, clientRect, leftAligned, bottomAligned; 1036 1037 if (this._o.container) return; 1038 1039 this.el.style.position = 'absolute'; 1040 1041 field = this._o.trigger; 1042 pEl = field; 1043 width = this.el.offsetWidth; 1044 height = this.el.offsetHeight; 1045 viewportWidth = window.innerWidth || document.documentElement.clientWidth; 1046 viewportHeight = window.innerHeight || document.documentElement.clientHeight; 1047 scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop; 1048 leftAligned = true; 1049 bottomAligned = true; 1050 1051 if (typeof field.getBoundingClientRect === 'function') { 1052 clientRect = field.getBoundingClientRect(); 1053 left = clientRect.left + window.pageXOffset; 1054 top = clientRect.bottom + window.pageYOffset; 1055 } else { 1056 left = pEl.offsetLeft; 1057 top = pEl.offsetTop + pEl.offsetHeight; 1058 while((pEl = pEl.offsetParent)) { 1059 left += pEl.offsetLeft; 1060 top += pEl.offsetTop; 1061 } 1062 } 1063 1064 // default position is bottom & left 1065 if ((this._o.reposition && left + width > viewportWidth) || 1066 ( 1067 this._o.position.indexOf('right') > -1 && 1068 left - width + field.offsetWidth > 0 1069 ) 1070 ) { 1071 left = left - width + field.offsetWidth; 1072 leftAligned = false; 1073 } 1074 if ((this._o.reposition && top + height > viewportHeight + scrollTop) || 1075 ( 1076 this._o.position.indexOf('top') > -1 && 1077 top - height - field.offsetHeight > 0 1078 ) 1079 ) { 1080 top = top - height - field.offsetHeight; 1081 bottomAligned = false; 1082 } 1083 1084 this.el.style.left = left + 'px'; 1085 this.el.style.top = top + 'px'; 1086 1087 addClass(this.el, leftAligned ? 'left-aligned' : 'right-aligned'); 1088 addClass(this.el, bottomAligned ? 'bottom-aligned' : 'top-aligned'); 1089 removeClass(this.el, !leftAligned ? 'left-aligned' : 'right-aligned'); 1090 removeClass(this.el, !bottomAligned ? 'bottom-aligned' : 'top-aligned'); 1091 }, 1092 1093 /** 1094 * render HTML for a particular month 1095 */ 1096 render: function(year, month, randId) 1097 { 1098 var opts = this._o, 1099 now = new Date(), 1100 days = getDaysInMonth(year, month), 1101 before = new Date(year, month, 1).getDay(), 1102 data = [], 1103 row = []; 1104 setToStartOfDay(now); 1105 if (opts.firstDay > 0) { 1106 before -= opts.firstDay; 1107 if (before < 0) { 1108 before += 7; 1109 } 1110 } 1111 var previousMonth = month === 0 ? 11 : month - 1, 1112 nextMonth = month === 11 ? 0 : month + 1, 1113 yearOfPreviousMonth = month === 0 ? year - 1 : year, 1114 yearOfNextMonth = month === 11 ? year + 1 : year, 1115 daysInPreviousMonth = getDaysInMonth(yearOfPreviousMonth, previousMonth); 1116 var cells = days + before, 1117 after = cells; 1118 while(after > 7) { 1119 after -= 7; 1120 } 1121 cells += 7 - after; 1122 var isWeekSelected = false; 1123 for (var i = 0, r = 0; i < cells; i++) 1124 { 1125 var day = new Date(year, month, 1 + (i - before)), 1126 isSelected = isDate(this._d) ? compareDates(day, this._d) : false, 1127 isToday = compareDates(day, now), 1128 hasEvent = opts.events.indexOf(day.toDateString()) !== -1 ? true : false, 1129 isEmpty = i < before || i >= (days + before), 1130 dayNumber = 1 + (i - before), 1131 monthNumber = month, 1132 yearNumber = year, 1133 isStartRange = opts.startRange && compareDates(opts.startRange, day), 1134 isEndRange = opts.endRange && compareDates(opts.endRange, day), 1135 isInRange = opts.startRange && opts.endRange && opts.startRange < day && day < opts.endRange, 1136 isDisabled = (opts.minDate && day < opts.minDate) || 1137 (opts.maxDate && day > opts.maxDate) || 1138 (opts.disableWeekends && isWeekend(day)) || 1139 (opts.disableDayFn && opts.disableDayFn(day)); 1140 1141 if (isEmpty) { 1142 if (i < before) { 1143 dayNumber = daysInPreviousMonth + dayNumber; 1144 monthNumber = previousMonth; 1145 yearNumber = yearOfPreviousMonth; 1146 } else { 1147 dayNumber = dayNumber - days; 1148 monthNumber = nextMonth; 1149 yearNumber = yearOfNextMonth; 1150 } 1151 } 1152 1153 var dayConfig = { 1154 day: dayNumber, 1155 month: monthNumber, 1156 year: yearNumber, 1157 hasEvent: hasEvent, 1158 isSelected: isSelected, 1159 isToday: isToday, 1160 isDisabled: isDisabled, 1161 isEmpty: isEmpty, 1162 isStartRange: isStartRange, 1163 isEndRange: isEndRange, 1164 isInRange: isInRange, 1165 showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths, 1166 enableSelectionDaysInNextAndPreviousMonths: opts.enableSelectionDaysInNextAndPreviousMonths 1167 }; 1168 1169 if (opts.pickWholeWeek && isSelected) { 1170 isWeekSelected = true; 1171 } 1172 1173 row.push(renderDay(dayConfig)); 1174 1175 if (++r === 7) { 1176 if (opts.showWeekNumber) { 1177 row.unshift(renderWeek(i - before, month, year)); 1178 } 1179 data.push(renderRow(row, opts.isRTL, opts.pickWholeWeek, isWeekSelected)); 1180 row = []; 1181 r = 0; 1182 isWeekSelected = false; 1183 } 1184 } 1185 return renderTable(opts, data, randId); 1186 }, 1187 1188 isVisible: function() 1189 { 1190 return this._v; 1191 }, 1192 1193 show: function() 1194 { 1195 if (!this.isVisible()) { 1196 this._v = true; 1197 this.draw(); 1198 removeClass(this.el, 'is-hidden'); 1199 if (this._o.bound) { 1200 addEvent(document, 'click', this._onClick); 1201 this.adjustPosition(); 1202 } 1203 if (typeof this._o.onOpen === 'function') { 1204 this._o.onOpen.call(this); 1205 } 1206 } 1207 }, 1208 1209 hide: function() 1210 { 1211 var v = this._v; 1212 if (v !== false) { 1213 if (this._o.bound) { 1214 removeEvent(document, 'click', this._onClick); 1215 } 1216 this.el.style.position = 'static'; // reset 1217 this.el.style.left = 'auto'; 1218 this.el.style.top = 'auto'; 1219 addClass(this.el, 'is-hidden'); 1220 this._v = false; 1221 if (v !== undefined && typeof this._o.onClose === 'function') { 1222 this._o.onClose.call(this); 1223 } 1224 } 1225 }, 1226 1227 /** 1228 * GAME OVER 1229 */ 1230 destroy: function() 1231 { 1232 var opts = this._o; 1233 1234 this.hide(); 1235 removeEvent(this.el, 'mousedown', this._onMouseDown, true); 1236 removeEvent(this.el, 'touchend', this._onMouseDown, true); 1237 removeEvent(this.el, 'change', this._onChange); 1238 if (opts.keyboardInput) { 1239 removeEvent(document, 'keydown', this._onKeyChange); 1240 } 1241 if (opts.field) { 1242 removeEvent(opts.field, 'change', this._onInputChange); 1243 if (opts.bound) { 1244 removeEvent(opts.trigger, 'click', this._onInputClick); 1245 removeEvent(opts.trigger, 'focus', this._onInputFocus); 1246 removeEvent(opts.trigger, 'blur', this._onInputBlur); 1247 } 1248 } 1249 if (this.el.parentNode) { 1250 this.el.parentNode.removeChild(this.el); 1251 } 1252 } 1253 1254 }; 1255 1256 return Pikaday; 1257}));
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.