PageSourceSearch

https://www.novuna.co.uk/App_Plugins/UmbracoForms/Assets/pikaday/pikaday.js

js novuna.co.uk collected 2026-10-03 19:45:13 UTC 43,167 bytes, 1,257 lines download raw bytes

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.