vendor: 41,941 bytes, lines 1-1273
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 (e) {} 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 (e) {} 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 lifted from date.js (MIT license): https://github.com/datejs/Datejs 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 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 tooltip = []; 310 var ariaSelected = 'false'; 311 if (opts.isEmpty) { 312 if (opts.showDaysInNextAndPreviousMonths) { 313 arr.push('is-outside-current-month'); 314 315 if(!opts.enableSelectionDaysInNextAndPreviousMonths) { 316 arr.push('is-selection-disabled'); 317 } 318 319 } else { 320 return '<td class="is-empty"></td>'; 321 } 322 } 323 if (opts.isDisabled) { 324 arr.push('is-disabled'); 325 } 326 if (opts.externalUserClass) { 327 if (typeof opts.externalUserClass === 'object') { 328 opts.externalUserClass.forEach (function (userClass) { 329 tooltip.push(userClass); 330 }); 331 } else { 332 tooltip.push (opts.externalUserClass); 333 } 334 } 335 if (opts.isToday) { 336 arr.push('is-today'); 337 } 338 if (opts.isSelected) { 339 arr.push('is-selected'); 340 ariaSelected = 'true'; 341 } 342 if (opts.hasEvent) { 343 arr.push('has-event'); 344 } 345 if (opts.isInRange) { 346 arr.push('is-inrange'); 347 } 348 if (opts.isStartRange) { 349 arr.push('is-startrange'); 350 } 351 if (opts.isEndRange) { 352 arr.push('is-endrange'); 353 } 354 return '<td data-day="' + opts.day + '" class="vi-nopart day-' +opts.year+'-'+opts.month+'-'+opts.day+' ' + arr.join(' ') + '" aria-selected="' + ariaSelected + '">' + 355 '<button title="'+tooltip.join(' ')+'" data-toggle="tooltip" role="tooltip" class="pika-button pika-day vi-nopart" type="button" ' + 356 'data-pika-year="' + opts.year + '" data-pika-month="' + opts.month + '" data-pika-day="' + opts.day + '">' + 357 opts.day + 358 '</button>' + 359 '</td>'; 360 }, 361 362 isoWeek = function(date) { 363 // Ensure we're at the start of the day. 364 date.setHours(0, 0, 0, 0); 365 366 // Thursday in current week decides the year because January 4th 367 // is always in the first week according to ISO8601. 368 369 var yearDay = date.getDate() 370 , weekDay = date.getDay() 371 , dayInFirstWeek = 4 // January 4th 372 , dayShift = dayInFirstWeek - 1 // counting starts at 0 373 , daysPerWeek = 7 374 , prevWeekDay = function(day) { return (day + daysPerWeek - 1) % daysPerWeek; } 375 ; 376 377 // Adjust to Thursday in week 1 and count number of weeks from date to week 1. 378 379 date.setDate(yearDay + dayShift - prevWeekDay(weekDay)); 380 381 var jan4th = new Date(date.getFullYear(), 0, dayInFirstWeek) 382 , msPerDay = 24 * 60 * 60 * 1000 383 , daysBetween = (date.getTime() - jan4th.getTime()) / msPerDay 384 , weekNum = 1 + Math.round((daysBetween - dayShift + prevWeekDay(jan4th.getDay())) / daysPerWeek) 385 ; 386 387 return weekNum; 388 }, 389 390 renderWeek = function (d, m, y) { 391 var date = new Date(y, m, d) 392 , week = hasMoment ? moment(date).isoWeek() : isoWeek(date) 393 ; 394 395 return '<td class="pika-week vi-nopart">' + week + '</td>'; 396 }, 397 398 renderRow = function(days, isRTL, pickWholeWeek, isRowSelected) 399 { 400 return '<tr class="pika-row vi-nopart' + (pickWholeWeek ? ' pick-whole-week' : '') + (isRowSelected ? ' is-selected' : '') + '">' + (isRTL ? days.reverse() : days).join('') + '</tr>'; 401 }, 402 403 renderBody = function(rows) 404 { 405 return '<tbody>' + rows.join('') + '</tbody>'; 406 }, 407 408 renderHead = function(opts) 409 { 410 var i, arr = []; 411 if (opts.showWeekNumber) { 412 arr.push('<th></th>'); 413 } 414 for (i = 0; i < 7; i++) { 415 arr.push('<th scope="col"><abbr title="' + renderDayName(opts, i) + '">' + renderDayName(opts, i, true) + '</abbr></th>'); 416 } 417 return '<thead><tr>' + (opts.isRTL ? arr.reverse() : arr).join('') + '</tr></thead>'; 418 }, 419 420 renderTitle = function(instance, c, year, month, refYear, randId) 421 { 422 var i, j, arr, 423 opts = instance._o, 424 isMinYear = year === opts.minYear, 425 isMaxYear = year === opts.maxYear, 426 html = '<div id="' + randId + '" class="pika-title vi-nopart" role="heading" aria-live="assertive">', 427 monthHtml, 428 yearHtml, 429 prev = true, 430 next = true; 431 432 for (arr = [], i = 0; i < 12; i++) { 433 arr.push('<option value="' + (year === refYear ? i - c : 12 + i - c) + '"' + 434 (i === month ? ' selected="selected"': '') + 435 ((isMinYear && i < opts.minMonth) || (isMaxYear && i > opts.maxMonth) ? ' disabled="disabled"' : '') + '>' + 436 opts.i18n.months[i] + '</option>'); 437 } 438 439 monthHtml = '<div class="pika-label vi-nopart">' + opts.i18n.months[month] + '<select class="pika-select pika-select-month" tabindex="-1">' + arr.join('') + '</select></div>'; 440 441 if (isArray(opts.yearRange)) { 442 i = opts.yearRange[0]; 443 j = opts.yearRange[1] + 1; 444 } else { 445 i = year - opts.yearRange; 446 j = 1 + year + opts.yearRange; 447 } 448 449 for (arr = []; i < j && i <= opts.maxYear; i++) { 450 if (i >= opts.minYear) { 451 arr.push('<option value="' + i + '"' + (i === year ? ' selected="selected"': '') + '>' + (i) + '</option>'); 452 } 453 } 454 yearHtml = '<div class="pika-label vi-nopart">' + year + opts.yearSuffix + '<select class="pika-select pika-select-year" tabindex="-1">' + arr.join('') + '</select></div>'; 455 456 if (opts.showMonthAfterYear) { 457 html += yearHtml + monthHtml; 458 } else { 459 html += monthHtml + yearHtml; 460 } 461 462 if (isMinYear && (month === 0 || opts.minMonth >= month)) { 463 prev = false; 464 } 465 466 if (isMaxYear && (month === 11 || opts.maxMonth <= month)) { 467 next = false; 468 } 469 470 if (c === 0) { 471 html += '<button class="pika-prev vi-nopart' + (prev ? '' : ' is-disabled') + '" type="button">' + opts.i18n.previousMonth + '</button>'; 472 } 473 if (c === (instance._o.numberOfMonths - 1) ) { 474 html += '<button class="pika-next vi-nopart' + (next ? '' : ' is-disabled') + '" type="button">' + opts.i18n.nextMonth + '</button>'; 475 } 476 477 return html += '</div>'; 478 }, 479 480 renderTable = function(opts, data, randId) 481 { 482 return '<table cellpadding="0" cellspacing="0" class="pika-table vi-nopart" role="grid" aria-labelledby="' + randId + '">' + renderHead(opts) + renderBody(data) + '</table>'; 483 }, 484 485 486 /** 487 * Pikaday constructor 488 */ 489 Pikaday = function(options) 490 { 491 var self = this, 492 opts = self.config(options); 493 494 self._onMouseDown = function(e) 495 { 496 if (!self._v) { 497 return; 498 } 499 e = e || window.event; 500 var target = e.target || e.srcElement; 501 if (!target) { 502 return; 503 } 504 505 if (!hasClass(target, 'is-disabled')) { 506 if (hasClass(target, 'pika-button') && !hasClass(target, 'is-empty') && !hasClass(target.parentNode, 'is-disabled')) { 507 self.setDate(new Date(target.getAttribute('data-pika-year'), target.getAttribute('data-pika-month'), target.getAttribute('data-pika-day'))); 508 if (opts.bound) { 509 sto(function() { 510 self.hide(); 511 if (opts.blurFieldOnSelect && opts.field) { 512 opts.field.blur(); 513 } 514 }, 100); 515 } 516 } 517 else if (hasClass(target, 'pika-prev')) { 518 self.prevMonth(); 519 } 520 else if (hasClass(target, 'pika-next')) { 521 self.nextMonth(); 522 } 523 } 524 if (!hasClass(target, 'pika-select')) { 525 // if this is touch event prevent mouse events emulation 526 if (e.preventDefault) { 527 e.preventDefault(); 528 } else { 529 e.returnValue = false; 530 return false; 531 } 532 } else { 533 self._c = true; 534 } 535 }; 536 537 self._onChange = function(e) 538 { 539 e = e || window.event; 540 var target = e.target || e.srcElement; 541 if (!target) { 542 return; 543 } 544 if (hasClass(target, 'pika-select-month')) { 545 self.gotoMonth(target.value); 546 } 547 else if (hasClass(target, 'pika-select-year')) { 548 self.gotoYear(target.value); 549 } 550 }; 551 552 self._onKeyChange = function(e) 553 { 554 e = e || window.event; 555 556 if (self.isVisible()) { 557 558 switch(e.keyCode){ 559 case 13: 560 case 27: 561 if (opts.field) { 562 opts.field.blur(); 563 } 564 break; 565 case 37: 566 self.adjustDate('subtract', 1); 567 break; 568 case 38: 569 self.adjustDate('subtract', 7); 570 break; 571 case 39: 572 self.adjustDate('add', 1); 573 break; 574 case 40: 575 self.adjustDate('add', 7); 576 break; 577 case 8: 578 case 46: 579 self.setDate(null); 580 break; 581 } 582 } 583 }; 584 585 self._parseFieldValue = function() 586 { 587 if (opts.parse) { 588 return opts.parse(opts.field.value, opts.format); 589 } else if (hasMoment) { 590 var date = moment(opts.field.value, opts.format, opts.formatStrict); 591 return (date && date.isValid()) ? date.toDate() : null; 592 } else { 593 return new Date(Date.parse(opts.field.value)); 594 } 595 }; 596 597 self._onInputChange = function(e) 598 { 599 var date; 600 601 if (e.firedBy === self) { 602 return; 603 } 604 date = self._parseFieldValue(); 605 if (isDate(date)) { 606 self.setDate(date); 607 } 608 if (!self._v) { 609 self.show(); 610 } 611 }; 612 613 self._onInputFocus = function() 614 { 615 self.show(); 616 }; 617 618 self._onInputClick = function() 619 { 620 self.show(); 621 }; 622 623 self._onInputBlur = function() 624 { 625 // IE allows pika div to gain focus; catch blur the input field 626 var pEl = document.activeElement; 627 do { 628 if (hasClass(pEl, 'pika-single')) { 629 return; 630 } 631 } 632 while ((pEl = pEl.parentNode)); 633 634 if (!self._c) { 635 self._b = sto(function() { 636 self.hide(); 637 }, 50); 638 } 639 self._c = false; 640 }; 641 642 self._onClick = function(e) 643 { 644 e = e || window.event; 645 var target = e.target || e.srcElement, 646 pEl = target; 647 if (!target) { 648 return; 649 } 650 if (!hasEventListeners && hasClass(target, 'pika-select')) { 651 if (!target.onchange) { 652 target.setAttribute('onchange', 'return;'); 653 addEvent(target, 'change', self._onChange); 654 } 655 } 656 do { 657 if (hasClass(pEl, 'pika-single') || pEl === opts.trigger) { 658 return; 659 } 660 } 661 while ((pEl = pEl.parentNode)); 662 if (self._v && target !== opts.trigger && pEl !== opts.trigger) { 663 self.hide(); 664 } 665 }; 666 667 self.el = document.createElement('div'); 668 self.el.className = 'pika-single' + (opts.isRTL ? ' is-rtl' : '') + (opts.theme ? ' ' + opts.theme : ''); 669 670 addEvent(self.el, 'mousedown', self._onMouseDown, true); 671 addEvent(self.el, 'touchend', self._onMouseDown, true); 672 addEvent(self.el, 'change', self._onChange); 673 674 if (opts.keyboardInput) { 675 addEvent(document, 'keydown', self._onKeyChange); 676 } 677 678 if (opts.field) { 679 if (opts.container) { 680 opts.container.appendChild(self.el); 681 } else if (opts.bound) { 682 document.body.appendChild(self.el); 683 } else { 684 opts.field.parentNode.insertBefore(self.el, opts.field.nextSibling); 685 } 686 addEvent(opts.field, 'change', self._onInputChange); 687 688 if (!opts.defaultDate) { 689 opts.defaultDate = self._parseFieldValue(); 690 opts.setDefaultDate = true; 691 } 692 } 693 694 var defDate = opts.defaultDate; 695 696 if (isDate(defDate)) { 697 if (opts.setDefaultDate) { 698 self.setDate(defDate, true); 699 } else { 700 self.gotoDate(defDate); 701 } 702 } else { 703 self.gotoDate(new Date()); 704 } 705 706 if (opts.bound) { 707 this.hide(); 708 self.el.className += ' is-bound'; 709 addEvent(opts.trigger, 'click', self._onInputClick); 710 addEvent(opts.trigger, 'focus', self._onInputFocus); 711 addEvent(opts.trigger, 'blur', self._onInputBlur); 712 } else { 713 this.show(); 714 } 715 }; 716 717 718 /** 719 * public Pikaday API 720 */ 721 Pikaday.prototype = { 722 723 724 /** 725 * configure functionality 726 */ 727 config: function(options) 728 { 729 if (!this._o) { 730 this._o = extend({}, defaults, true); 731 } 732 733 var opts = extend(this._o, options, true); 734 735 opts.isRTL = !!opts.isRTL; 736 737 opts.field = (opts.field && opts.field.nodeName) ? opts.field : null; 738 739 opts.theme = (typeof opts.theme) === 'string' && opts.theme ? opts.theme : null; 740 741 opts.bound = !!(opts.bound !== undefined ? opts.field && opts.bound : opts.field); 742 743 opts.trigger = (opts.trigger && opts.trigger.nodeName) ? opts.trigger : opts.field; 744 745 opts.disableWeekends = !!opts.disableWeekends; 746 747 opts.disableDayFn = (typeof opts.disableDayFn) === 'function' ? opts.disableDayFn : null; 748 749 opts.userClassFn = (typeof opts.userClassFn) === 'function' ? opts.userClassFn : null; 750 751 var nom = parseInt(opts.numberOfMonths, 10) || 1; 752 opts.numberOfMonths = nom > 4 ? 4 : nom; 753 754 if (!isDate(opts.minDate)) { 755 opts.minDate = false; 756 } 757 if (!isDate(opts.maxDate)) { 758 opts.maxDate = false; 759 } 760 if ((opts.minDate && opts.maxDate) && opts.maxDate < opts.minDate) { 761 opts.maxDate = opts.minDate = false; 762 } 763 if (opts.minDate) { 764 this.setMinDate(opts.minDate); 765 } 766 if (opts.maxDate) { 767 this.setMaxDate(opts.maxDate); 768 } 769 770 if (isArray(opts.yearRange)) { 771 var fallback = new Date().getFullYear() - 10; 772 opts.yearRange[0] = parseInt(opts.yearRange[0], 10) || fallback; 773 opts.yearRange[1] = parseInt(opts.yearRange[1], 10) || fallback; 774 } else { 775 opts.yearRange = Math.abs(parseInt(opts.yearRange, 10)) || defaults.yearRange; 776 if (opts.yearRange > 100) { 777 opts.yearRange = 100; 778 } 779 } 780 781 return opts; 782 }, 783 784 /** 785 * return a formatted string of the current selection (using Moment.js if available) 786 */ 787 toString: function(format) 788 { 789 format = format || this._o.format; 790 if (!isDate(this._d)) { 791 return ''; 792 } 793 if (this._o.toString) { 794 return this._o.toString(this._d, format); 795 } 796 if (hasMoment) { 797 return moment(this._d).format(format); 798 } 799 return this._d.toDateString(); 800 }, 801 802 /** 803 * return a Moment.js object of the current selection (if available) 804 */ 805 getMoment: function() 806 { 807 return hasMoment ? moment(this._d) : null; 808 }, 809 810 /** 811 * set the current selection from a Moment.js object (if available) 812 */ 813 setMoment: function(date, preventOnSelect) 814 { 815 if (hasMoment && moment.isMoment(date)) { 816 this.setDate(date.toDate(), preventOnSelect); 817 } 818 }, 819 820 /** 821 * return a Date object of the current selection 822 */ 823 getDate: function() 824 { 825 return isDate(this._d) ? new Date(this._d.getTime()) : null; 826 }, 827 828 /** 829 * set the current selection 830 */ 831 setDate: function(date, preventOnSelect) 832 { 833 if (!date) { 834 this._d = null; 835 836 if (this._o.field) { 837 this._o.field.value = ''; 838 fireEvent(this._o.field, 'change', { firedBy: this }); 839 } 840 841 return this.draw(); 842 } 843 if (typeof date === 'string') { 844 date = new Date(Date.parse(date)); 845 } 846 if (!isDate(date)) { 847 return; 848 } 849 850 var min = this._o.minDate, 851 max = this._o.maxDate; 852 853 if (isDate(min) && date < min) { 854 date = min; 855 } else if (isDate(max) && date > max) { 856 date = max; 857 } 858 859 this._d = new Date(date.getTime()); 860 setToStartOfDay(this._d); 861 this.gotoDate(this._d); 862 863 if (this._o.field) { 864 this._o.field.value = this.toString(); 865 fireEvent(this._o.field, 'change', { firedBy: this }); 866 } 867 if (!preventOnSelect && typeof this._o.onSelect === 'function') { 868 this._o.onSelect.call(this, this.getDate()); 869 } 870 }, 871 872 /** 873 * clear and reset the date 874 */ 875 clear: function() 876 { 877 this.setDate(null); 878 }, 879 880 /** 881 * change view to a specific date 882 */ 883 gotoDate: function(date) 884 { 885 var newCalendar = true; 886 887 if (!isDate(date)) { 888 return; 889 } 890 891 if (this.calendars) { 892 var firstVisibleDate = new Date(this.calendars[0].year, this.calendars[0].month, 1), 893 lastVisibleDate = new Date(this.calendars[this.calendars.length-1].year, this.calendars[this.calendars.length-1].month, 1), 894 visibleDate = date.getTime(); 895 // get the end of the month 896 lastVisibleDate.setMonth(lastVisibleDate.getMonth()+1); 897 lastVisibleDate.setDate(lastVisibleDate.getDate()-1); 898 newCalendar = (visibleDate < firstVisibleDate.getTime() || lastVisibleDate.getTime() < visibleDate); 899 } 900 901 if (newCalendar) { 902 this.calendars = [{ 903 month: date.getMonth(), 904 year: date.getFullYear() 905 }]; 906 if (this._o.mainCalendar === 'right') { 907 this.calendars[0].month += 1 - this._o.numberOfMonths; 908 } 909 } 910 911 this.adjustCalendars(); 912 }, 913 914 adjustDate: function(sign, days) { 915 916 var day = this.getDate() || new Date(); 917 var difference = parseInt(days)*24*60*60*1000; 918 919 var newDay; 920 921 if (sign === 'add') { 922 newDay = new Date(day.valueOf() + difference); 923 } else if (sign === 'subtract') { 924 newDay = new Date(day.valueOf() - difference); 925 } 926 927 this.setDate(newDay); 928 }, 929 930 adjustCalendars: function() { 931 this.calendars[0] = adjustCalendar(this.calendars[0]); 932 for (var c = 1; c < this._o.numberOfMonths; c++) { 933 this.calendars[c] = adjustCalendar({ 934 month: this.calendars[0].month + c, 935 year: this.calendars[0].year 936 }); 937 } 938 this.draw(); 939 }, 940 941 gotoToday: function() 942 { 943 this.gotoDate(new Date()); 944 }, 945 946 /** 947 * change view to a specific month (zero-index, e.g. 0: January) 948 */ 949 gotoMonth: function(month) 950 { 951 if (!isNaN(month)) { 952 this.calendars[0].month = parseInt(month, 10); 953 this.adjustCalendars(); 954 } 955 }, 956 957 nextMonth: function() 958 { 959 this.calendars[0].month++; 960 this.adjustCalendars(); 961 $("#calendar .pika-day").tooltip({"html": true,"container": "body"}); 962 }, 963 964 prevMonth: function() 965 { 966 this.calendars[0].month--; 967 this.adjustCalendars(); 968 $("#calendar .pika-day").tooltip({"html": true,"container": "body"}); 969 }, 970 971 /** 972 * change view to a specific full year (e.g. "2012") 973 */ 974 gotoYear: function(year) 975 { 976 if (!isNaN(year)) { 977 this.calendars[0].year = parseInt(year, 10); 978 this.adjustCalendars(); 979 } 980 }, 981 982 /** 983 * change the minDate 984 */ 985 setMinDate: function(value) 986 { 987 if(value instanceof Date) { 988 setToStartOfDay(value); 989 this._o.minDate = value; 990 this._o.minYear = value.getFullYear(); 991 this._o.minMonth = value.getMonth(); 992 } else { 993 this._o.minDate = defaults.minDate; 994 this._o.minYear = defaults.minYear; 995 this._o.minMonth = defaults.minMonth; 996 this._o.startRange = defaults.startRange; 997 } 998 999 this.draw(); 1000 }, 1001 1002 /** 1003 * change the maxDate 1004 */ 1005 setMaxDate: function(value) 1006 { 1007 if(value instanceof Date) { 1008 setToStartOfDay(value); 1009 this._o.maxDate = value; 1010 this._o.maxYear = value.getFullYear(); 1011 this._o.maxMonth = value.getMonth(); 1012 } else { 1013 this._o.maxDate = defaults.maxDate; 1014 this._o.maxYear = defaults.maxYear; 1015 this._o.maxMonth = defaults.maxMonth; 1016 this._o.endRange = defaults.endRange; 1017 } 1018 1019 this.draw(); 1020 }, 1021 1022 setStartRange: function(value) 1023 { 1024 this._o.startRange = value; 1025 }, 1026 1027 setEndRange: function(value) 1028 { 1029 this._o.endRange = value; 1030 }, 1031 1032 /** 1033 * refresh the HTML 1034 */ 1035 draw: function(force) 1036 { 1037 if (!this._v && !force) { 1038 return; 1039 } 1040 var opts = this._o, 1041 minYear = opts.minYear, 1042 maxYear = opts.maxYear, 1043 minMonth = opts.minMonth, 1044 maxMonth = opts.maxMonth, 1045 html = '', 1046 randId; 1047 1048 if (this._y <= minYear) { 1049 this._y = minYear; 1050 if (!isNaN(minMonth) && this._m < minMonth) { 1051 this._m = minMonth; 1052 } 1053 } 1054 if (this._y >= maxYear) { 1055 this._y = maxYear; 1056 if (!isNaN(maxMonth) && this._m > maxMonth) { 1057 this._m = maxMonth; 1058 } 1059 } 1060 1061 for (var c = 0; c < opts.numberOfMonths; c++) { 1062 randId = 'pika-title-' + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 2); 1063 html += '<div class="pika-lendar vi-nopart">' + 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>'; 1064 } 1065 1066 this.el.innerHTML = html; 1067 1068 if (opts.bound) { 1069 if(opts.field.type !== 'hidden') { 1070 sto(function() { 1071 opts.trigger.focus(); 1072 }, 1); 1073 } 1074 } 1075 1076 if (typeof this._o.onDraw === 'function') { 1077 this._o.onDraw(this); 1078 } 1079 1080 if (opts.bound) { 1081 // let the screen reader user know to use arrow keys 1082 opts.field.setAttribute('aria-label', opts.ariaLabel); 1083 } 1084 }, 1085 1086 adjustPosition: function() 1087 { 1088 var field, pEl, width, height, viewportWidth, viewportHeight, scrollTop, left, top, clientRect, leftAligned, bottomAligned; 1089 1090 if (this._o.container) return; 1091 1092 this.el.style.position = 'absolute'; 1093 1094 field = this._o.trigger; 1095 pEl = field; 1096 width = this.el.offsetWidth; 1097 height = this.el.offsetHeight; 1098 viewportWidth = window.innerWidth || document.documentElement.clientWidth; 1099 viewportHeight = window.innerHeight || document.documentElement.clientHeight; 1100 scrollTop = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop; 1101 leftAligned = true; 1102 bottomAligned = true; 1103 1104 if (typeof field.getBoundingClientRect === 'function') { 1105 clientRect = field.getBoundingClientRect(); 1106 left = clientRect.left + window.pageXOffset; 1107 top = clientRect.bottom + window.pageYOffset; 1108 } else { 1109 left = pEl.offsetLeft; 1110 top = pEl.offsetTop + pEl.offsetHeight; 1111 while((pEl = pEl.offsetParent)) { 1112 left += pEl.offsetLeft; 1113 top += pEl.offsetTop; 1114 } 1115 } 1116 1117 // default position is bottom & left 1118 if ((this._o.reposition && left + width > viewportWidth) || 1119 ( 1120 this._o.position.indexOf('right') > -1 && 1121 left - width + field.offsetWidth > 0 1122 ) 1123 ) { 1124 left = left - width + field.offsetWidth; 1125 leftAligned = false; 1126 } 1127 if ((this._o.reposition && top + height > viewportHeight + scrollTop) || 1128 ( 1129 this._o.position.indexOf('top') > -1 && 1130 top - height - field.offsetHeight > 0 1131 ) 1132 ) { 1133 top = top - height - field.offsetHeight; 1134 bottomAligned = false; 1135 } 1136 1137 this.el.style.left = left + 'px'; 1138 this.el.style.top = top + 'px'; 1139 1140 addClass(this.el, leftAligned ? 'left-aligned' : 'right-aligned'); 1141 addClass(this.el, bottomAligned ? 'bottom-aligned' : 'top-aligned'); 1142 removeClass(this.el, !leftAligned ? 'left-aligned' : 'right-aligned'); 1143 removeClass(this.el, !bottomAligned ? 'bottom-aligned' : 'top-aligned'); 1144 }, 1145 1146 /** 1147 * render HTML for a particular month 1148 */ 1149 render: function(year, month, randId) 1150 { 1151 var opts = this._o, 1152 now = new Date(), 1153 days = getDaysInMonth(year, month), 1154 before = new Date(year, month, 1).getDay(), 1155 data = [], 1156 row = []; 1157 setToStartOfDay(now); 1158 if (opts.firstDay > 0) { 1159 before -= opts.firstDay; 1160 if (before < 0) { 1161 before += 7; 1162 } 1163 } 1164 var previousMonth = month === 0 ? 11 : month - 1, 1165 nextMonth = month === 11 ? 0 : month + 1, 1166 yearOfPreviousMonth = month === 0 ? year - 1 : year, 1167 yearOfNextMonth = month === 11 ? year + 1 : year, 1168 daysInPreviousMonth = getDaysInMonth(yearOfPreviousMonth, previousMonth); 1169 var cells = days + before, 1170 after = cells; 1171 while(after > 7) { 1172 after -= 7; 1173 } 1174 cells += 7 - after; 1175 var isWeekSelected = false; 1176 for (var i = 0, r = 0; i < cells; i++) 1177 { 1178 var day = new Date(year, month, 1 + (i - before)), 1179 isSelected = isDate(this._d) ? compareDates(day, this._d) : false, 1180 isToday = compareDates(day, now), 1181 hasEvent = opts.events.indexOf(day.toDateString()) !== -1 ? true : false, 1182 isEmpty = i < before || i >= (days + before), 1183 dayNumber = 1 + (i - before), 1184 monthNumber = month, 1185 yearNumber = year, 1186 isStartRange = opts.startRange && compareDates(opts.startRange, day), 1187 isEndRange = opts.endRange && compareDates(opts.endRange, day), 1188 isInRange = opts.startRange && opts.endRange && opts.startRange < day && day < opts.endRange, 1189 isDisabled = (opts.minDate && day < opts.minDate) || 1190 (opts.maxDate && day > opts.maxDate) || 1191 (opts.disableWeekends && isWeekend(day)) || 1192 (opts.disableDayFn && opts.disableDayFn(day)), 1193 externalUserClass = opts.userClassFn && opts.userClassFn (day); 1194 1195 if (isEmpty) { 1196 if (i < before) { 1197 dayNumber = daysInPreviousMonth + dayNumber; 1198 monthNumber = previousMonth; 1199 yearNumber = yearOfPreviousMonth; 1200 } else { 1201 dayNumber = dayNumber - days; 1202 monthNumber = nextMonth; 1203 yearNumber = yearOfNextMonth; 1204 } 1205 } 1206 1207 var dayConfig = { 1208 day: dayNumber, 1209 month: monthNumber, 1210 year: yearNumber, 1211 hasEvent: hasEvent, 1212 isSelected: isSelected, 1213 isToday: isToday, 1214 isDisabled: isDisabled, 1215 isEmpty: isEmpty, 1216 isStartRange: isStartRange, 1217 isEndRange: isEndRange, 1218 isInRange: isInRange, 1219 showDaysInNextAndPreviousMonths: opts.showDaysInNextAndPreviousMonths, 1220 enableSelectionDaysInNextAndPreviousMonths: opts.enableSelectionDaysInNextAndPreviousMonths, 1221 externalUserClass: externalUserClass 1222 }; 1223 1224 if (opts.pickWholeWeek && isSelected) { 1225 isWeekSelected = true; 1226 } 1227 1228 row.push(renderDay(dayConfig)); 1229 1230 if (++r === 7) { 1231 if (opts.showWeekNumber) { 1232 row.unshift(renderWeek(i - before, month, year)); 1233 } 1234 data.push(renderRow(row, opts.isRTL, opts.pickWholeWeek, isWeekSelected)); 1235 row = []; 1236 r = 0; 1237 isWeekSelected = false; 1238 } 1239 } 1240 return renderTable(opts, data, randId); 1241 }, 1242 1243 isVisible: function() 1244 { 1245 return this._v; 1246 }, 1247 1248 show: function() 1249 { 1250 if (!this.isVisible()) { 1251 this._v = true; 1252 this.draw(); 1253 removeClass(this.el, 'is-hidden'); 1254 if (this._o.bound) { 1255 addEvent(document, 'click', this._onClick); 1256 this.adjustPosition(); 1257 } 1258 if (typeof this._o.onOpen === 'function') { 1259 this._o.onOpen.call(this); 1260 } 1261 } 1262 }, 1263 1264 hide: function() 1265 { 1266 var v = this._v; 1267 if (v !== false) { 1268 if (this._o.bound) { 1269 removeEvent(document, 'click', this._onClick); 1270 } 1271 this.el.style.position = 'static'; // reset 1272 this.el.style.left = 'auto'; 1273 this.el.style.top = 'auto';
vendor: 1,266 bytes, lines 1273-1312
1273 1274 addClass(this.el, 'is-hidden'); 1275 this._v = false; 1276 if (v !== undefined && typeof this._o.onClose === 'function') { 1277 this._o.onClose.call(this); 1278 } 1279 } 1280 }, 1281 1282 /** 1283 * GAME OVER 1284 */ 1285 destroy: function() 1286 { 1287 var opts = this._o; 1288 1289 this.hide(); 1290 removeEvent(this.el, 'mousedown', this._onMouseDown, true); 1291 removeEvent(this.el, 'touchend', this._onMouseDown, true); 1292 removeEvent(this.el, 'change', this._onChange); 1293 if (opts.keyboardInput) { 1294 removeEvent(document, 'keydown', this._onKeyChange); 1295 } 1296 if (opts.field) { 1297 removeEvent(opts.field, 'change', this._onInputChange); 1298 if (opts.bound) { 1299 removeEvent(opts.trigger, 'click', this._onInputClick); 1300 removeEvent(opts.trigger, 'focus', this._onInputFocus); 1301 removeEvent(opts.trigger, 'blur', this._onInputBlur); 1302 } 1303 } 1304 if (this.el.parentNode) { 1305 this.el.parentNode.removeChild(this.el); 1306 } 1307 } 1308 1309 }; 1310 1311 return Pikaday; 1312}));
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.