PageSourceSearch

https://unitedshop.com/scripts/lib/datepicker.js

js unitedshop.com collected 2026-10-04 10:38:48 UTC 77,297 bytes, 1,920 lines download raw bytes

1
2(function ($, undefined) {
3
4    function UTCDate() {
5        return new Date(Date.UTC.apply(Date, arguments));
6    }
7    function UTCToday() {
8        var today = new Date();
9        return UTCDate(today.getFullYear(), today.getMonth(), today.getDate());
10    }
11    function isUTCEquals(date1, date2) {
12        return (
13            date1.getUTCFullYear() === date2.getUTCFullYear() &&
14            date1.getUTCMonth() === date2.getUTCMonth() &&
15            date1.getUTCDate() === date2.getUTCDate()
16        );
17    }
18    function alias(method) {
19        return function () {
20            return this[method].apply(this, arguments);
21        };
22    }
23
24    var DateArray = (function () {
25        var extras = {
26            get: function (i) {
27                return this.slice(i)[0];
28            },
29            contains: function (d) {
30                // Array.indexOf is not cross-browser;
31                // $.inArray doesn't work with Dates
32                var val = d && d.valueOf();
33                for (var i = 0, l = this.length; i < l; i++)
34                    if (this[i].valueOf() === val)
35                        return i;
36                return -1;
37            },
38            remove: function (i) {
39                this.splice(i, 1);
40            },
41            replace: function (new_array) {
42                if (!new_array)
43                    return;
44                if (!$.isArray(new_array))
45                    new_array = [new_array];
46                this.clear();
47                this.push.apply(this, new_array);
48            },
49            clear: function () {
50                this.length = 0;
51            },
52            copy: function () {
53                var a = new DateArray();
54                a.replace(this);
55                return a;
56            }
57        };
58
59        return function () {
60            var a = [];
61            a.push.apply(a, arguments);
62            $.extend(a, extras);
63            return a;
64        };
65    })();
66
67
68    // Picker object
69
70    var Datepicker = function (element, options) {
71        this._process_options(options);
72
73        this.dates = new DateArray();
74        this.viewDate = this.o.defaultViewDate;
75        this.focusDate = null;
76
77        this.element = $(element);
78        this.isInline = false;
79        this.isInput = this.element.is('input');
80        this.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .btn') : false;
81        this.hasInput = this.component && this.element.find('input').length;
82        if (this.component && this.component.length === 0)
83            this.component = false;
84
85        this.picker = $(DPGlobal.template);
86        this._buildEvents();
87        this._attachEvents();
88
89        if (this.isInline) {
90            this.picker.addClass('datepicker-inline').appendTo(this.element);
91        }
92        else {
93            this.picker.addClass('datepicker-dropdown dropdown-menu');
94        }
95
96        if (this.o.rtl) {
97            this.picker.addClass('datepicker-rtl');
98        }
99
100        this.viewMode = this.o.startView;
101
102        if (this.o.calendarWeeks)
103            this.picker.find('tfoot .today, tfoot .clear')
104                .attr('colspan', function (i, val) {
105                    return parseInt(val) + 1;
106                });
107
108        this._allow_update = false;
109
110        this.setStartDate(this._o.startDate);
111        this.setEndDate(this._o.endDate);
112        this.setDaysOfWeekDisabled(this.o.daysOfWeekDisabled);
113        this.setDatesDisabled(this.o.datesDisabled);
114
115        this.fillDow();
116        this.fillMonths();
117
118        this._allow_update = true;
119
120        this.update();
121        this.showMode();
122
123        if (this.isInline) {
124            this.show();
125        }
126    };
127
128    Datepicker.prototype = {
129        constructor: Datepicker,
130
131        _process_options: function (opts) {
132            // Store raw options for reference
133            this._o = $.extend({}, this._o, opts);
134            // Processed options
135            var o = this.o = $.extend({}, this._o);
136
137            // Check if "de-DE" style date is available, if not language should
138            // fallback to 2 letter code eg "de"
139            var lang = o.language;
140            if (!dates[lang]) {
141                lang = lang.split('-')[0];
142                if (!dates[lang])
143                    lang = defaults.language;
144            }
145            o.language = lang;
146
147            switch (o.startView) {
148                case 2:
149                case 'decade':
150                    o.startView = 2;
151                    break;
152                case 1:
153                case 'year':
154                    o.startView = 1;
155                    break;
156                default:
157                    o.startView = 0;
158            }
159
160            switch (o.minViewMode) {
161                case 1:
162                case 'months':
163                    o.minViewMode = 1;
164                    break;
165                case 2:
166                case 'years':
167                    o.minViewMode = 2;
168                    break;
169                default:
170                    o.minViewMode = 0;
171            }
172
173            o.startView = Math.max(o.startView, o.minViewMode);
174
175            // true, false, or Number > 0
176            if (o.multidate !== true) {
177                o.multidate = Number(o.multidate) || false;
178                if (o.multidate !== false)
179                    o.multidate = Math.max(0, o.multidate);
180            }
181            o.multidateSeparator = String(o.multidateSeparator);
182
183            o.weekStart %= 7;
184            o.weekEnd = ((o.weekStart + 6) % 7);
185
186            var format = DPGlobal.parseFormat(o.format);
187            if (o.startDate !== -Infinity) {
188                if (!!o.startDate) {
189                    if (o.startDate instanceof Date)
190                        o.startDate = this._local_to_utc(this._zero_time(o.startDate));
191                    else
192                        o.startDate = DPGlobal.parseDate(o.startDate, format, o.language);
193                }
194                else {
195                    o.startDate = -Infinity;
196                }
197            }
198            if (o.endDate !== Infinity) {
199                if (!!o.endDate) {
200                    if (o.endDate instanceof Date)
201                        o.endDate = this._local_to_utc(this._zero_time(o.endDate));
202                    else
203                        o.endDate = DPGlobal.parseDate(o.endDate, format, o.language);
204                }
205                else {
206                    o.endDate = Infinity;
207                }
208            }
209
210            o.daysOfWeekDisabled = o.daysOfWeekDisabled || [];
211            if (!$.isArray(o.daysOfWeekDisabled))
212                o.daysOfWeekDisabled = o.daysOfWeekDisabled.split(/[,\s]*/);
213            o.daysOfWeekDisabled = $.map(o.daysOfWeekDisabled, function (d) {
214                return parseInt(d, 10);
215            });
216
217            o.datesDisabled = o.datesDisabled || [];
218            if (!$.isArray(o.datesDisabled)) {
219                var datesDisabled = [];
220                datesDisabled.push(DPGlobal.parseDate(o.datesDisabled, format, o.language));
221                o.datesDisabled = datesDisabled;
222            }
223            o.datesDisabled = $.map(o.datesDisabled, function (d) {
224                return DPGlobal.parseDate(d, format, o.language);
225            });
226
227            var plc = String(o.orientation).toLowerCase().split(/\s+/g),
228                _plc = o.orientation.toLowerCase();
229            plc = $.grep(plc, function (word) {
230                return /^auto|left|right|top|bottom$/.test(word);
231            });
232            o.orientation = { x: 'auto', y: 'auto' };
233            if (!_plc || _plc === 'auto')
234                ; // no action
235            else if (plc.length === 1) {
236                switch (plc[0]) {
237                    case 'top':
238                    case 'bottom':
239                        o.orientation.y = plc[0];
240                        break;
241                    case 'left':
242                    case 'right':
243                        o.orientation.x = plc[0];
244                        break;
245                }
246            }
247            else {
248                _plc = $.grep(plc, function (word) {
249                    return /^left|right$/.test(word);
250                });
251                o.orientation.x = _plc[0] || 'auto';
252
253                _plc = $.grep(plc, function (word) {
254                    return /^top|bottom$/.test(word);
255                });
256                o.orientation.y = _plc[0] || 'auto';
257            }
258            if (o.defaultViewDate) {
259                var year = o.defaultViewDate.year || new Date().getFullYear();
260                var month = o.defaultViewDate.month || 0;
261                var day = o.defaultViewDate.day || 1;
262                o.defaultViewDate = UTCDate(year, month, day);
263            } else {
264                o.defaultViewDate = UTCToday();
265            }
266            o.showOnFocus = o.showOnFocus !== undefined ? o.showOnFocus : true;
267        },
268        _events: [],
269        _secondaryEvents: [],
270        _applyEvents: function (evs) {
271            for (var i = 0, el, ch, ev; i < evs.length; i++) {
272                el = evs[i][0];
273                if (evs[i].length === 2) {
274                    ch = undefined;
275                    ev = evs[i][1];
276                }
277                else if (evs[i].length === 3) {
278                    ch = evs[i][1];
279                    ev = evs[i][2];
280                }
281                el.on(ev, ch);
282            }
283        },
284        _unapplyEvents: function (evs) {
285            for (var i = 0, el, ev, ch; i < evs.length; i++) {
286                el = evs[i][0];
287                if (evs[i].length === 2) {
288                    ch = undefined;
289                    ev = evs[i][1];
290                }
291                else if (evs[i].length === 3) {
292                    ch = evs[i][1];
293                    ev = evs[i][2];
294                }
295                el.off(ev, ch);
296            }
297        },
298        _buildEvents: function () {
299            var events = {
300                keyup: $.proxy(function (e) {
301                    if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)
302                        this.update();
303                }, this),
304                keydown: $.proxy(this.keydown, this),
305                paste: $.proxy(this.paste, this)
306            };
307
308            if (this.o.showOnFocus === true) {
309                events.focus = $.proxy(this.show, this);
310            }
311
312            if (this.isInput) { // single input
313                this._events = [
314                    [this.element, events]
315                ];
316            }
317            else if (this.component && this.hasInput) { // component: input + button
318                this._events = [
319                    // For components that are not readonly, allow keyboard nav
320                    [this.element.find('input'), events],
321                    [this.component, {
322                        click: $.proxy(this.show, this)
323                    }]
324                ];
325            }
326            else if (this.element.is('div')) {  // inline datepicker
327                this.isInline = true;
328            }
329            else {
330                this._events = [
331                    [this.element, {
332                        click: $.proxy(this.show, this)
333                    }]
334                ];
335            }
336            this._events.push(
337                // Component: listen for blur on element descendants
338                [this.element, '*', {
339                    blur: $.proxy(function (e) {
340                        this._focused_from = e.target;
341                    }, this)
342                }],
343                // Input: listen for blur on element
344                [this.element, {
345                    blur: $.proxy(function (e) {
346                        this._focused_from = e.target;
347                    }, this)
348                }]
349            );
350
351            this._secondaryEvents = [
352                [this.picker, {
353                    click: $.proxy(this.click, this)
354                }],
355                [$(window), {
356                    resize: $.proxy(this.place, this)
357                }],
358                [$(document), {
359                    mousedown: $.proxy(function (e) {
360                        // Clicked outside the datepicker, hide it
361                        if (!(
362                            this.element.is(e.target) ||
363                            this.element.find(e.target).length ||
364                            this.picker.is(e.target) ||
365                            this.picker.find(e.target).length
366                        )) {
367                            $(this.picker).hide();
368                        }
369                    }, this)
370                }]
371            ];
372        },
373        _attachEvents: function () {
374            this._detachEvents();
375            this._applyEvents(this._events);
376        },
377        _detachEvents: function () {
378            this._unapplyEvents(this._events);
379        },
380        _attachSecondaryEvents: function () {
381            this._detachSecondaryEvents();
382            this._applyEvents(this._secondaryEvents);
383        },
384        _detachSecondaryEvents: function () {
385            this._unapplyEvents(this._secondaryEvents);
386        },
387        _trigger: function (event, altdate) {
388            var date = altdate || this.dates.get(-1),
389                local_date = this._utc_to_local(date);
390
391            this.element.trigger({
392                type: event,
393                date: local_date,
394                dates: $.map(this.dates, this._utc_to_local),
395                format: $.proxy(function (ix, format) {
396                    if (arguments.length === 0) {
397                        ix = this.dates.length - 1;
398                        format = this.o.format;
399                    }
400                    else if (typeof ix === 'string') {
401                        format = ix;
402                        ix = this.dates.length - 1;
403                    }
404                    format = format || this.o.format;
405                    var date = this.dates.get(ix);
406                    return DPGlobal.formatDate(date, format, this.o.language);
407                }, this)
408            });
409        },
410
411        show: function () {
412            if (this.element.attr('readonly') && this.o.enableOnReadonly === false)
413                return;
414            if (!this.isInline)
415                this.picker.appendTo(this.o.container);
416            this.place();
417            this.picker.show();
418            this._attachSecondaryEvents();
419            this._trigger('show');
420            if ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) {
421                $(this.element).blur();
422            }
423            return this;
424        },
425
426        hide: function () {
427            if (this.isInline)
428                return this;
429            if (!this.picker.is(':visible'))
430                return this;
431            this.focusDate = null;
432            this.picker.hide().detach();
433            this._detachSecondaryEvents();
434            this.viewMode = this.o.startView;
435            this.showMode();
436
437            if (
438                this.o.forceParse &&
439                (
440                    this.isInput && this.element.val() ||
441                    this.hasInput && this.element.find('input').val()
442                )
443            )
444                this.setValue();
445            this._trigger('hide');
446            return this;
447        },
448
449        remove: function () {
450            this.hide();
451            this._detachEvents();
452            this._detachSecondaryEvents();
453            this.picker.remove();
454            delete this.element.data().datepicker;
455            if (!this.isInput) {
456                delete this.element.data().date;
457            }
458            return this;
459        },
460
461        paste: function (evt) {
462            var dateString;
463            if (evt.originalEvent.clipboardData && evt.originalEvent.clipboardData.types
464                && $.inArray('text/plain', evt.originalEvent.clipboardData.types) !== -1) {
465                dateString = evt.originalEvent.clipboardData.getData('text/plain');
466            }
467            else if (window.clipboardData) {
468                dateString = window.clipboardData.getData('Text');
469            }
470            else {
471                return;
472            }
473            this.setDate(dateString);
474            this.update();
475            evt.preventDefault();
476        },
477
478        _utc_to_local: function (utc) {
479            return utc && new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));
480        },
481        _local_to_utc: function (local) {
482            return local && new Date(local.getTime() - (local.getTimezoneOffset() * 60000));
483        },
484        _zero_time: function (local) {
485            return local && new Date(local.getFullYear(), local.getMonth(), local.getDate());
486        },
487        _zero_utc_time: function (utc) {
488            return utc && new Date(Date.UTC(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate()));
489        },
490
491        getDates: function () {
492            return $.map(this.dates, this._utc_to_local);
493        },
494
495        getUTCDates: function () {
496            return $.map(this.dates, function (d) {
497                return new Date(d);
498            });
499        },
500
501        getDate: function () {
502            return this._utc_to_local(this.getUTCDate());
503        },
504
505        getUTCDate: function () {
506            var selected_date = this.dates.get(-1);
507            if (typeof selected_date !== 'undefined') {
508                return new Date(selected_date);
509            } else {
510                return null;
511            }
512        },
513
514        clearDates: function () {
515            var element;
516            if (this.isInput) {
517                element = this.element;
518            } else if (this.component) {
519                element = this.element.find('input');
520            }
521
522            if (element) {
523                element.val('').change();
524            }
525
526            this.update();
527            this._trigger('changeDate');
528
529            if (this.o.autoclose) {
530                this.hide();
531            }
532        },
533        setDates: function () {
534            var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
535            this.update.apply(this, args);
536            this._trigger('changeDate');
537            this.setValue();
538            return this;
539        },
540
541        setUTCDates: function () {
542            var args = $.isArray(arguments[0]) ? arguments[0] : arguments;
543            this.update.apply(this, $.map(args, this._utc_to_local));
544            this._trigger('changeDate');
545            this.setValue();
546            return this;
547        },
548
549        setDate: alias('setDates'),
550        setUTCDate: alias('setUTCDates'),
551
552        setValue: function () {
553            var formatted = this.getFormattedDate();
554            if (!this.isInput) {
555                if (this.component) {
556                    this.element.find('input').val(formatted).change();
557                }
558            }
559            else {
560                this.element.val(formatted).change();
561                var AttributeId = this.element[0].id;
562                var dateObject = $('input#' + AttributeId).val();
563                if (dateObject != null) {
564                    $("input#" + AttributeId).removeClass("input-validation-error");
565                    $("#errorSpam" + AttributeId).find("span").remove();
566                }
567            }
568            return this;
569        },
570
571        getFormattedDate: function (format) {
572            if (format === undefined)
573                format = this.o.format;
574
575            var lang = this.o.language;
576            return $.map(this.dates, function (d) {
577                return DPGlobal.formatDate(d, format, lang);
578            }).join(this.o.multidateSeparator);
579        },
580
581        setStartDate: function (startDate) {
582            this._process_options({ startDate: startDate });
583            this.update();
584            this.updateNavArrows();
585            return this;
586        },
587
588        setEndDate: function (endDate) {
589            this._process_options({ endDate: endDate });
590            this.update();
591            this.updateNavArrows();
592            return this;
593        },
594
595        setDaysOfWeekDisabled: function (daysOfWeekDisabled) {
596            this._process_options({ daysOfWeekDisabled: daysOfWeekDisabled });
597            this.update();
598            this.updateNavArrows();
599            return this;
600        },
601
602        setDatesDisabled: function (datesDisabled) {
603            this._process_options({ datesDisabled: datesDisabled });
604            this.update();
605            this.updateNavArrows();
606        },
607
608        place: function () {
609            if (this.isInline)
610                return this;
611            var calendarWidth = this.picker.outerWidth(),
612                calendarHeight = this.picker.outerHeight(),
613                visualPadding = 10,
614                windowWidth = $(this.o.container).width(),
615                windowHeight = $(this.o.container).height(),
616                scrollTop = $(this.o.container).scrollTop(),
617                appendOffset = $(this.o.container).offset();
618
619            var parentsZindex = [];
620            this.element.parents().each(function () {
621                var itemZIndex = $(this).css('z-index');
622                if (itemZIndex !== 'auto' && itemZIndex !== 0) parentsZindex.push(parseInt(itemZIndex));
623            });
624            var zIndex = Math.max.apply(Math, parentsZindex) + 10;
625            var offset = this.component ? this.component.parent().offset() : this.element.offset();
626            var height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);
627            var width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);
628            var left = offset.left - appendOffset.left,
629                top = offset.top - appendOffset.top;
630
631            this.picker.removeClass(
632                'datepicker-orient-top datepicker-orient-bottom ' +
633                'datepicker-orient-right datepicker-orient-left'
634            );
635
636            if (this.o.orientation.x !== 'auto') {
637                this.picker.addClass('datepicker-orient-' + this.o.orientation.x);
638                if (this.o.orientation.x === 'right')
639                    left -= calendarWidth - width;
640            }
641            // auto x orientation is best-placement: if it crosses a window
642            // edge, fudge it sideways
643            else {
644                if (offset.left < 0) {
645                    // component is outside the window on the left side. Move it into visible range
646                    this.picker.addClass('datepicker-orient-left');
647                    left -= offset.left - visualPadding;
648                } else if (left + calendarWidth > windowWidth) {
649                    // the calendar passes the widow right edge. Align it to component right side
650                    this.picker.addClass('datepicker-orient-right');
651                    left = offset.left + width - calendarWidth;
652                } else {
653                    // Default to left
654                    this.picker.addClass('datepicker-orient-left');
655                }
656            }
657
658            // auto y orientation is best-situation: top or bottom, no fudging,
659            // decision based on which shows more of the calendar
660            var yorient = this.o.orientation.y,
661                top_overflow, bottom_overflow;
662            if (yorient === 'auto') {
663                top_overflow = -scrollTop + top - calendarHeight;
664                bottom_overflow = scrollTop + windowHeight - (top + height + calendarHeight);
665                if (Math.max(top_overflow, bottom_overflow) === bottom_overflow)
666                    yorient = 'top';
667                else
668                    yorient = 'bottom';
669            }
670            this.picker.addClass('datepicker-orient-' + yorient);
671            if (yorient === 'top')
672                top += height;
673            else
674                top -= calendarHeight + parseInt(this.picker.css('padding-top'));
675
676            if (this.o.rtl) {
677                var right = windowWidth - (left + width);
678                this.picker.css({
679                    top: top,
680                    right: right,
681                    zIndex: zIndex
682                });
683            } else {
684                this.picker.css({
685                    top: top,
686                    left: left,
687                    zIndex: zIndex
688                });
689            }
690            return this;
691        },
692
693        _allow_update: true,
694        update: function () {
695            if (!this._allow_update)
696                return this;
697
698            var oldDates = this.dates.copy(),
699                dates = [],
700                fromArgs = false;
701            if (arguments.length) {
702                $.each(arguments, $.proxy(function (i, date) {
703                    if (date instanceof Date)
704                        date = this._local_to_utc(date);
705                    dates.push(date);
706                }, this));
707                fromArgs = true;
708            }
709            else {
710                dates = this.isInput
711                    ? this.element.val()
712                    : this.element.data('date') || this.element.find('input').val();
713                if (dates && this.o.multidate)
714                    dates = dates.split(this.o.multidateSeparator);
715                else
716                    dates = [dates];
717                delete this.element.data().date;
718            }
719
720            dates = $.map(dates, $.proxy(function (date) {
721                return DPGlobal.parseDate(date, this.o.format, this.o.language);
722            }, this));
723            dates = $.grep(dates, $.proxy(function (date) {
724                return (
725                    date < this.o.startDate ||
726                    date > this.o.endDate ||
727                    !date
728                );
729            }, this), true);
730            this.dates.replace(dates);
731
732            if (this.dates.length)
733                this.viewDate = new Date(this.dates.get(-1));
734            else if (this.viewDate < this.o.startDate)
735                this.viewDate = new Date(this.o.startDate);
736            else if (this.viewDate > this.o.endDate)
737                this.viewDate = new Date(this.o.endDate);
738
739            if (fromArgs) {
740                // setting date by clicking
741                this.setValue();
742            }
743            else if (dates.length) {
744                // setting date by typing
745                if (String(oldDates) !== String(this.dates))
746                    this._trigger('changeDate');
747            }
748            if (!this.dates.length && oldDates.length)
749                this._trigger('clearDate');
750
751            this.fill();
752            return this;
753        },
754
755        fillDow: function () {
756            var dowCnt = this.o.weekStart,
757                html = '<tr>';
758            if (this.o.calendarWeeks) {
759                this.picker.find('.datepicker-days thead tr:first-child .datepicker-switch')
760                    .attr('colspan', function (i, val) {
761                        return parseInt(val) + 1;
762                    });
763                var cell = '<th class="cw">&#160;</th>';
764                html += cell;
765            }
766            while (dowCnt < this.o.weekStart + 7) {
767                html += '<th class="dow">' + dates[this.o.language].daysShort[(dowCnt++) % 7] + '</th>';
768            }
769            html += '</tr>';
770            this.picker.find('.datepicker-days thead').append(html);
771        },
772
773        fillMonths: function () {
774            var html = '',
775                i = 0;
776            while (i < 12) {
777                html += '<span class="month">' + dates[this.o.language].monthsShort[i++] + '</span>';
778            }
779            this.picker.find('.datepicker-months td').html(html);
780        },
781
782        setRange: function (range) {
783            if (!range || !range.length)
784                delete this.range;
785            else
786                this.range = $.map(range, function (d) {
787                    return d.valueOf();
788                });
789            this.fill();
790        },
791
792        getClassNames: function (date) {
793            var cls = [],
794                year = this.viewDate.getUTCFullYear(),
795                month = this.viewDate.getUTCMonth(),
796                today = new Date();
797            if (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)) {
798                cls.push('old');
799            }
800            else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)) {
801                cls.push('new');
802            }
803            if (this.focusDate && date.valueOf() === this.focusDate.valueOf())
804                cls.push('focused');
805            // Compare internal UTC date with local today, not UTC today
806            if (this.o.todayHighlight &&
807                date.getUTCFullYear() === today.getFullYear() &&
808                date.getUTCMonth() === today.getMonth() &&
809                date.getUTCDate() === today.getDate()) {
810                cls.push('today');
811            }
812            if (this.dates.contains(date) !== -1)
813                cls.push('active');
814            if (date.valueOf() < this.o.startDate || date.valueOf() > this.o.endDate ||
815                $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1) {
816                cls.push('disabled');
817            }
818            if (this.o.datesDisabled.length > 0 &&
819                $.grep(this.o.datesDisabled, function (d) {
820                    return isUTCEquals(date, d);
821                }).length > 0) {
822                cls.push('disabled', 'disabled-date');
823            }
824
825            if (this.range) {
826                if (date > this.range[0] && date < this.range[this.range.length - 1]) {
827                    cls.push('range');
828                }
829                if ($.inArray(date.valueOf(), this.range) !== -1) {
830                    cls.push('selected');
831                }
832            }
833            return cls;
834        },
835
836        fill: function () {
837            var d = new Date(this.viewDate),
838                year = d.getUTCFullYear(),
839                month = d.getUTCMonth(),
840                startYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,
841                startMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,
842                endYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,
843                endMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,
844                todaytxt = dates[this.o.language].today || dates['en'].today || '',
845                cleartxt = dates[this.o.language].clear || dates['en'].clear || '',
846                tooltip;
847            if (isNaN(year) || isNaN(month))
848                return;
849            this.picker.find('.datepicker-days thead .datepicker-switch')
850                .text(dates[this.o.language].months[month] + ' ' + year);
851            this.picker.find('tfoot .today')
852                .text(todaytxt)
853                .toggle(this.o.todayBtn !== false);
854            this.picker.find('tfoot .clear')
855                .text(cleartxt)
856                .toggle(this.o.clearBtn !== false);
857            this.updateNavArrows();
858            this.fillMonths();
859            var prevMonth = UTCDate(year, month - 1, 28),
860                day = DPGlobal.getDaysInMonth(prevMonth.getUTCFullYear(), prevMonth.getUTCMonth());
861            prevMonth.setUTCDate(day);
862            prevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7) % 7);
863            var nextMonth = new Date(prevMonth);
864            nextMonth.setUTCDate(nextMonth.getUTCDate() + 42);
865            nextMonth = nextMonth.valueOf();
866            var html = [];
867            var clsName;
868            while (prevMonth.valueOf() < nextMonth) {
869                if (prevMonth.getUTCDay() === this.o.weekStart) {
870                    html.push('<tr>');
871                    if (this.o.calendarWeeks) {
872                        // ISO 8601: First week contains first thursday.
873                        // ISO also states week starts on Monday, but we can be more abstract here.
874                        var
875                            // Start of current week: based on weekstart/current date
876                            ws = new Date(+prevMonth + (this.o.weekStart - prevMonth.getUTCDay() - 7) % 7 * 864e5),
877                            // Thursday of this week
878                            th = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),
879                            // First Thursday of year, year from thursday
880                            yth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5),
881                            // Calendar week: ms between thursdays, div ms per day, div 7 days
882                            calWeek = (th - yth) / 864e5 / 7 + 1;
883                        html.push('<td class="cw">' + calWeek + '</td>');
884
885                    }
886                }
887                clsName = this.getClassNames(prevMonth);
888                clsName.push('day');
889
890                if (this.o.beforeShowDay !== $.noop) {
891                    var before = this.o.beforeShowDay(this._utc_to_local(prevMonth));
892                    if (before === undefined)
893                        before = {};
894                    else if (typeof (before) === 'boolean')
895                        before = { enabled: before };
896                    else if (typeof (before) === 'string')
897                        before = { classes: before };
898                    if (before.enabled === false)
899                        clsName.push('disabled');
900                    if (before.classes)
901                        clsName = clsName.concat(before.classes.split(/\s+/));
902                    if (before.tooltip)
903                        tooltip = before.tooltip;
904                }
905
906                clsName = $.unique(clsName);
907                html.push('<td class="' + clsName.join(' ') + '"' + (tooltip ? ' title="' + tooltip + '"' : '') + '>
907' + prevMonth.getUTCDate() + '</td>');
908                tooltip = null;
909                if (prevMonth.getUTCDay() === this.o.weekEnd) {
910                    html.push('</tr>');
911                }
912                prevMonth.setUTCDate(prevMonth.getUTCDate() + 1);
913            }
914            this.picker.find('.datepicker-days tbody').empty().append(html.join(''));
915
916            var months = this.picker.find('.datepicker-months')
917                .find('th:eq(1)')
918                .text(year)
919                .end()
920                .find('span').removeClass('active');
921
922            $.each(this.dates, function (i, d) {
923                if (d.getUTCFullYear() === year)
924                    months.eq(d.getUTCMonth()).addClass('active');
925            });
926
927            if (year < startYear || year > endYear) {
928                months.addClass('disabled');
929            }
930            if (year === startYear) {
931                months.slice(0, startMonth).addClass('disabled');
932            }
933            if (year === endYear) {
934                months.slice(endMonth + 1).addClass('disabled');
935            }
936
937            if (this.o.beforeShowMonth !== $.noop) {
938                var that = this;
939                $.each(months, function (i, month) {
940                    if (!$(month).hasClass('disabled')) {
941                        var moDate = new Date(year, i, 1);
942                        var before = that.o.beforeShowMonth(moDate);
943                        if (before === false)
944                            $(month).addClass('disabled');
945                    }
946                });
947            }
948
949            html = '';
950            year = parseInt(year / 10, 10) * 10;
951            var yearCont = this.picker.find('.datepicker-years')
952                .find('th:eq(1)')
953                .text(year + '-' + (year + 9))
954                .end()
955                .find('td');
956            year -= 1;
957            var years = $.map(this.dates, function (d) {
958                return d.getUTCFullYear();
959            }),
960                classes;
961            for (var i = -1; i < 11; i++) {
962                classes = ['year'];
963                if (i === -1)
964                    classes.push('old');
965                else if (i === 10)
966                    classes.push('new');
967                if ($.inArray(year, years) !== -1)
968                    classes.push('active');
969                if (year < startYear || year > endYear)
970                    classes.push('disabled');
971                html += '<span class="' + classes.join(' ') + '">' + year + '</span>';
972                year += 1;
973            }
974            yearCont.html(html);
975        },
976
977        updateNavArrows: function () {
978            if (!this._allow_update)
979                return;
980
981            var d = new Date(this.viewDate),
982                year = d.getUTCFullYear(),
983                month = d.getUTCMonth();
984            switch (this.viewMode) {
985                case 0:
986                    if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear() && month <= this.o.startDate.getUTCMonth()) {
987                        this.picker.find('.prev').css({ visibility: 'hidden' });
988                    }
989                    else {
990                        this.picker.find('.prev').css({ visibility: 'visible' });
991                    }
992                    if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear() && month >= this.o.endDate.getUTCMonth()) {
993                        this.picker.find('.next').css({ visibility: 'hidden' });
994                    }
995                    else {
996                        this.picker.find('.next').css({ visibility: 'visible' });
997                    }
998                    break;
999                case 1:
1000                case 2:
1001                    if (this.o.startDate !== -Infinity && year <= this.o.startDate.getUTCFullYear()) {
1002                        this.picker.find('.prev').css({ visibility: 'hidden' });
1003                    }
1004                    else {
1005                        this.picker.find('.prev').css({ visibility: 'visible' });
1006                    }
1007                    if (this.o.endDate !== Infinity && year >= this.o.endDate.getUTCFullYear()) {
1008                        this.picker.find('.next').css({ visibility: 'hidden' });
1009                    }
1010                    else {
1011                        this.picker.find('.next').css({ visibility: 'visible' });
1012                    }
1013                    break;
1014            }
1015        },
1016
1017        click: function (e) {
1018            e.preventDefault();
1019            var target = $(e.target).closest('span, td, th'),
1020                year, month, day;
1021            if (target.length === 1) {
1022                switch (target[0].nodeName.toLowerCase()) {
1023                    case 'th':
1024                        switch (target[0].className) {
1025                            case 'datepicker-switch':
1026                                this.showMode(1);
1027                                break;
1028                            case 'prev':
1029                            case 'next':
1030                                var dir = DPGlobal.modes[this.viewMode].navStep * (target[0].className === 'prev' ? -1 : 1);
1031                                switch (this.viewMode) {
1032                                    case 0:
1033                                        this.viewDate = this.moveMonth(this.viewDate, dir);
1034                                        this._trigger('changeMonth', this.viewDate);
1035                                        break;
1036                                    case 1:
1037                                    case 2:
1038                                        this.viewDate = this.moveYear(this.viewDate, dir);
1039                                        if (this.viewMode === 1)
1040                                            this._trigger('changeYear', this.viewDate);
1041                                        break;
1042                                }
1043                                this.fill();
1044                                break;
1045                            case 'today':
1046                                var date = new Date();
1047                                date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
1048
1049                                this.showMode(-2);
1050                                var which = this.o.todayBtn === 'linked' ? null : 'view';
1051                                this._setDate(date, which);
1052                                break;
1053                            case 'clear':
1054                                this.clearDates();
1055                                break;
1056                        }
1057                        break;
1058                    case 'span':
1059                        if (!target.hasClass('disabled')) {
1060                            this.viewDate.setUTCDate(1);
1061                            if (target.hasClass('month')) {
1062                                day = 1;
1063                                month = target.parent().find('span').index(target);
1064                                year = this.viewDate.getUTCFullYear();
1065                                this.viewDate.setUTCMonth(month);
1066                                this._trigger('changeMonth', this.viewDate);
1067                                if (this.o.minViewMode === 1) {
1068                                    this._setDate(UTCDate(year, month, day));
1069                                }
1070                            }
1071                            else {
1072                                day = 1;
1073                                month = 0;
1074                                year = parseInt(target.text(), 10) || 0;
1075                                this.viewDate.setUTCFullYear(year);
1076                                this._trigger('changeYear', this.viewDate);
1077                                if (this.o.minViewMode === 2) {
1078                                    this._setDate(UTCDate(year, month, day));
1079                                }
1080                            }
1081                            this.showMode(-1);
1082                            this.fill();
1083                        }
1084                        break;
1085                    case 'td':
1086                        if (target.hasClass('day') && !target.hasClass('disabled')) {
1087                            day = parseInt(target.text(), 10) || 1;
1088                            year = this.viewDate.getUTCFullYear();
1089                            month = this.viewDate.getUTCMonth();
1090                            if (target.hasClass('old')) {
1091                                if (month === 0) {
1092                                    month = 11;
1093                                    year -= 1;
1094                                }
1095                                else {
1096                                    month -= 1;
1097                                }
1098                            }
1099                            else if (target.hasClass('new')) {
1100                                if (month === 11) {
1101                                    month = 0;
1102                                    year += 1;
1103                                }
1104                                else {
1105                                    month += 1;
1106                                }
1107                            }
1108                            this._setDate(UTCDate(year, month, day));
1109                        }
1110                        break;
1111                }
1112            }
1113            if (this.picker.is(':visible') && this._focused_from) {
1114                $(this._focused_from).focus();
1115            }
1116            delete this._focused_from;
1117        },
1118
1119        _toggle_multidate: function (date) {
1120            var ix = this.dates.contains(date);
1121            if (!date) {
1122                this.dates.clear();
1123            }
1124
1125            if (ix !== -1) {
1126                if (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive) {
1127                    this.dates.remove(ix);
1128                }
1129            } else if (this.o.multidate === false) {
1130                this.dates.clear();
1131                this.dates.push(date);
1132            }
1133            else {
1134                this.dates.push(date);
1135            }
1136
1137            if (typeof this.o.multidate === 'number')
1138                while (this.dates.length > this.o.multidate)
1139                    this.dates.remove(0);
1140        },
1141
1142        _setDate: function (date, which) {
1143            if (!which || which === 'date')
1144                this._toggle_multidate(date && new Date(date));
1145            if (!which || which === 'view')
1146                this.viewDate = date && new Date(date);
1147
1148            this.fill();
1149            this.setValue();
1150            if (!which || which !== 'view') {
1151                this._trigger('changeDate');
1152            }
1153            var element;
1154            if (this.isInput) {
1155                element = this.element;
1156            }
1157            else if (this.component) {
1158                element = this.element.find('input');
1159            }
1160            if (element) {
1161                element.change();
1162            }
1163            if (this.o.autoclose && (!which || which === 'date')) {
1164                this.hide();
1165            }
1166        },
1167
1168        moveMonth: function (date, dir) {
1169            if (!date)
1170                return undefined;
1171            if (!dir)
1172                return date;
1173            var new_date = new Date(date.valueOf()),
1174                day = new_date.getUTCDate(),
1175                month = new_date.getUTCMonth(),
1176                mag = Math.abs(dir),
1177                new_month, test;
1178            dir = dir > 0 ? 1 : -1;
1179            if (mag === 1) {
1180                test = dir === -1
1181                    // If going back one month, make sure month is not current month
1182                    // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
1183                    ? function () {
1184                        return new_date.getUTCMonth() === month;
1185                    }
1186                    // If going forward one month, make sure month is as expected
1187                    // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
1188                    : function () {
1189                        return new_date.getUTCMonth() !== new_month;
1190                    };
1191                new_month = month + dir;
1192                new_date.setUTCMonth(new_month);
1193                // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
1194                if (new_month < 0 || new_month > 11)
1195                    new_month = (new_month + 12) % 12;
1196            }
1197            else {
1198                // For magnitudes >1, move one month at a time...
1199                for (var i = 0; i < mag; i++)
1200                    // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
1201                    new_date = this.moveMonth(new_date, dir);
1202                // ...then reset the day, keeping it in the new month
1203                new_month = new_date.getUTCMonth();
1204                new_date.setUTCDate(day);
1205                test = function () {
1206                    return new_month !== new_date.getUTCMonth();
1207                };
1208            }
1209            // Common date-resetting loop -- if date is beyond end of month, make it
1210            // end of month
1211            while (test()) {
1212                new_date.setUTCDate(--day);
1213                new_date.setUTCMonth(new_month);
1214            }
1215            return new_date;
1216        },
1217
1218        moveYear: function (date, dir) {
1219            return this.moveMonth(date, dir * 12);
1220        },
1221
1222        dateWithinRange: function (date) {
1223            return date >= this.o.startDate && date <= this.o.endDate;
1224        },
1225
1226        keydown: function (e) {
1227            if (!this.picker.is(':visible')) {
1228                if (e.keyCode === 40 || e.keyCode === 27) // allow down to re-show picker
1229                    this.show();
1230                return;
1231            }
1232            var dateChanged = false,
1233                dir, newDate, newViewDate,
1234                focusDate = this.focusDate || this.viewDate;
1235            switch (e.keyCode) {
1236                case 27: // escape
1237                    if (this.focusDate) {
1238                        this.focusDate = null;
1239                        this.viewDate = this.dates.get(-1) || this.viewDate;
1240                        this.fill();
1241                    }
1242                    else {
1243                        this.hide();
1244                    }
1245                    $('.table-condensed').closest('.popover').hide();
1246                    e.preventDefault();
1247                    break;
1248                case 37: // left
1249                case 39: // right
1250                    if (!this.o.keyboardNavigation)
1251                        break;
1252                    dir = e.keyCode === 37 ? -1 : 1;
1253                    if (e.ctrlKey) {
1254                        newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
1255                        newViewDate = this.moveYear(focusDate, dir);
1256                        this._trigger('changeYear', this.viewDate);
1257                    }
1258                    else if (e.shiftKey) {
1259                        newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
1260                        newViewDate = this.moveMonth(focusDate, dir);
1261                        this._trigger('changeMonth', this.viewDate);
1262                    }
1263                    else {
1264                        newDate = new Date(this.dates.get(-1) || UTCToday());
1265                        newDate.setUTCDate(newDate.getUTCDate() + dir);
1266                        newViewDate = new Date(focusDate);
1267                        newViewDate.setUTCDate(focusDate.getUTCDate() + dir);
1268                    }
1269                    if (this.dateWithinRange(newViewDate)) {
1270                        this.focusDate = this.viewDate = newViewDate;
1271                        this.setValue();
1272                        this.fill();
1273                        this.announceDate(newViewDate);
1274                        e.preventDefault();
1275                    }
1276                    break;
1277                case 38: // up
1278                case 40: // down
1279                    if (!this.o.keyboardNavigation)
1280                        break;
1281                    dir = e.keyCode === 38 ? -1 : 1;
1282                    if (e.ctrlKey) {
1283                        newDate = this.moveYear(this.dates.get(-1) || UTCToday(), dir);
1284                        newViewDate = this.moveYear(focusDate, dir);
1285                        this._trigger('changeYear', this.viewDate);
1286                    }
1287                    else if (e.shiftKey) {
1288                        newDate = this.moveMonth(this.dates.get(-1) || UTCToday(), dir);
1289                        newViewDate = this.moveMonth(focusDate, dir);
1290                        this._trigger('changeMonth', this.viewDate);
1291                    }
1292                    else {
1293                        newDate = new Date(this.dates.get(-1) || UTCToday());
1294                        newDate.setUTCDate(newDate.getUTCDate() + dir * 7);
1295                        newViewDate = new Date(focusDate);
1296                        newViewDate.setUTCDate(focusDate.getUTCDate() + dir * 7);
1297                    }
1298                    if (this.dateWithinRange(newViewDate)) {
1299                        this.focusDate = this.viewDate = newViewDate;
1300                        this.setValue();
1301                        this.fill();
1302                        this.announceDate(newViewDate);
1303                        e.preventDefault();
1304                    }
1305                    break;
1306                case 32: // spacebar
1307                    // Spacebar is used in manually typing dates in some formats.
1308                    // As such, its behavior should not be hijacked.
1309                    break;
1310                case 13: // enter
1311                    focusDate = this.focusDate || this.dates.get(-1) || this.viewDate;
1312                    if (this.o.keyboardNavigation) {
1313                        this._toggle_multidate(focusDate);
1314                        dateChanged = true;
1315                    }
1316                    this.focusDate = null;
1317                    this.viewDate = this.dates.get(-1) || this.viewDate;
1318                    this.setValue();
1319                    this.fill();
1320                    this.announceDate(this.viewDate);
1321                    if (this.picker.is(':visible')) {
1322                        e.preventDefault();
1323                        if (typeof e.stopPropagation === 'function') {
1324                            e.stopPropagation(); // All modern browsers, IE9+
1325                        } else {
1326                            e.cancelBubble = true; // IE6,7,8 ignore "stopPropagation"
1327                        }
1328                        if (this.o.autoclose)
1329                            this.hide();
1330                    }
1331                    break;
1332                case 9: // tab
1333                    this.focusDate = null;
1334                    this.viewDate = this.dates.get(-1) || this.viewDate;
1335                    this.fill();
1336                    this.hide();
1337                    break;
1338            }
1339            if (dateChanged) {
1340                if (this.dates.length)
1341                    this._trigger('changeDate');
1342                else
1343                    this._trigger('clearDate');
1344                var element;
1345                if (this.isInput) {
1346                    element = this.element;
1347                }
1348                else if (this.component) {
1349                    element = this.element.find('input');
1350                }
1351                if (element) {
1352                    element.change();
1353                }
1354            }
1355        },
1356
1357        // Function to announce the selected date for screen readers
1358        announceDate: function (date) {
1359            var liveRegion = document.getElementById('datepicker-live-region');
1360            if (!liveRegion) {
1361                liveRegion = document.createElement('div');
1362                liveRegion.id = 'datepicker-live-region';
1363                liveRegion.setAttribute('role', 'alert');
1364                liveRegion.setAttribute('aria-live', 'assertive');
1365                document.body.appendChild(liveRegion);
1366            }
1367            liveRegion.textContent = "Selected date: " + date.toLocaleDateString("en-US", {
1368                weekday: "long",
1369                year: "numeric",
1370                month: "long",
1371                day: "numeric"
1372            });
1373        },
1374
1375        showMode: function (dir) {
1376            if (dir) {
1377                this.viewMode = Math.max(this.o.minViewMode, Math.min(2, this.viewMode + dir));
1378            }
1379            this.picker
1380                .children('div')
1381                .hide()
1382                .filter('.datepicker-' + DPGlobal.modes[this.viewMode].clsName)
1383                .css('display', 'block');
1384            this.updateNavArrows();
1385        }
1386    };
1387
1388    var DateRangePicker = function (element, options) {
1389        this.element = $(element);
1390        this.inputs = $.map(options.inputs, function (i) {
1391            return i.jquery ? i[0] : i;
1392        });
1393        delete options.inputs;
1394
1395        datepickerPlugin.call($(this.inputs), options)
1396            .on('changeDate', $.proxy(this.dateUpdated, this));
1397
1398        this.pickers = $.map(this.inputs, function (i) {
1399            return $(i).data('datepicker');
1400        });
1401        this.updateDates();
1402    };
1403    DateRangePicker.prototype = {
1404        updateDates: function () {
1405            this.dates = $.map(this.pickers, function (i) {
1406                return i.getUTCDate();
1407            });
1408            this.updateRanges();
1409        },
1410        updateRanges: function () {
1411            var range = $.map(this.dates, function (d) {
1412                return d.valueOf();
1413            });
1414            $.each(this.pickers, function (i, p) {
1415                p.setRange(range);
1416            });
1417        },
1418        dateUpdated: function (e) {
1419            // `this.updating` is a workaround for preventing infinite recursion
1420            // between `changeDate` triggering and `setUTCDate` calling.  Until
1421            // there is a better mechanism.
1422            if (this.updating)
1423                return;
1424            this.updating = true;
1425
1426            var dp = $(e.target).data('datepicker'),
1427                new_date = dp.getUTCDate(),
1428                i = $.inArray(e.target, this.inputs),
1429                j = i - 1,
1430                k = i + 1,
1431                l = this.inputs.length;
1432            if (i === -1)
1433                return;
1434
1435            $.each(this.pickers, function (i, p) {
1436                if (!p.getUTCDate())
1437                    p.setUTCDate(new_date);
1438            });
1439
1440            if (new_date < this.dates[j]) {
1441                // Date being moved earlier/left
1442                while (j >= 0 && new_date < this.dates[j]) {
1443                    this.pickers[j--].setUTCDate(new_date);
1444                }
1445            }
1446            else if (new_date > this.dates[k]) {
1447                // Date being moved later/right
1448                while (k < l && new_date > this.dates[k]) {
1449                    this.pickers[k++].setUTCDate(new_date);
1450                }
1451            }
1452            this.updateDates();
1453
1454            delete this.updating;
1455        },
1456        remove: function () {
1457            $.map(this.pickers, function (p) { p.remove(); });
1458            delete this.element.data().datepicker;
1459        }
1460    };
1461
1462    function opts_from_el(el, prefix) {
1463        // Derive options from element data-attrs
1464        var data = $(el).data(),
1465            out = {}, inkey,
1466            replace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');
1467        prefix = new RegExp('^' + prefix.toLowerCase());
1468        function re_lower(_, a) {
1469            return a.toLowerCase();
1470        }
1471        for (var key in data)
1472            if (prefix.test(key)) {
1473                inkey = key.replace(replace, re_lower);
1474                out[inkey] = data[key];
1475            }
1476        return out;
1477    }
1478
1479    function opts_from_locale(lang) {
1480        // Derive options from locale plugins
1481        var out = {};
1482        // Check if "de-DE" style date is available, if not language should
1483        // fallback to 2 letter code eg "de"
1484        if (!dates[lang]) {
1485            lang = lang.split('-')[0];
1486            if (!dates[lang])
1487                return;
1488        }
1489        var d = dates[lang];
1490        $.each(locale_opts, function (i, k) {
1491            if (k in d)
1492                out[k] = d[k];
1493        });
1494        return out;
1495    }
1496
1497    var old = $.fn.datepicker;
1498    var datepickerPlugin = function (option) {
1499        var args = Array.apply(null, arguments);
1500        args.shift();
1501        var internal_return;
1502        this.each(function () {
1503            var $this = $(this),
1504                data = $this.data('datepicker'),
1505                options = typeof option === 'object' && option;
1506            if (!data) {
1507                var elopts = opts_from_el(this, 'date'),
1508                    // Preliminary otions
1509                    xopts = $.extend({}, defaults, elopts, options),
1510                    locopts = opts_from_locale(xopts.language),
1511                    // Options priority: js args, data-attrs, locales, defaults
1512                    opts = $.extend({}, defaults, locopts, elopts, options);
1513                if ($this.hasClass('input-daterange') || opts.inputs) {
1514                    var ropts = {
1515                        inputs: opts.inputs || $this.find('input').toArray()
1516                    };
1517                    $this.data('datepicker', (data = new DateRangePicker(this, $.extend(opts, ropts))));
1518                }
1519                else {
1520                    $this.data('datepicker', (data = new Datepicker(this, opts)));
1521                }
1522            }
1523            if (typeof option === 'string' && typeof data[option] === 'function') {
1524                internal_return = data[option].apply(data, args);
1525                if (internal_return !== undefined)
1526                    return false;
1527            }
1528        });
1529        if (internal_return !== undefined)
1530            return internal_return;
1531        else
1532            return this;
1533    };
1534    $.fn.datepicker = datepickerPlugin;
1535
1536    var defaults = $.fn.datepicker.defaults = {
1537        autoclose: true,
1538        beforeShowDay: $.noop,
1539        beforeShowMonth: $.noop,
1540        calendarWeeks: false,
1541        clearBtn: true,
1542        toggleActive: false,
1543        daysOfWeekDisabled: [],
1544        datesDisabled: [],
1545        endDate: Infinity,
1546        forceParse: true,
1547        format: 'mm/dd/yyyy',
1548        keyboardNavigation: true,
1549        language: 'en',
1550        minViewMode: 0,
1551        multidate: false,
1552        multidateSeparator: ',',
1553        orientation: "auto",
1554        rtl: false,
1555        startDate: -Infinity,
1556        startView: 0,
1557        todayBtn: false,
1558        todayHighlight: false,
1559        weekStart: 0,
1560        disableTouchKeyboard: false,
1561        enableOnReadonly: true,
1562        container: 'body'
1563    };
1564    var locale_opts = $.fn.datepicker.locale_opts = [
1565        'format',
1566        'rtl',
1567        'weekStart'
1568    ];
1569    $.fn.datepicker.Constructor = Datepicker;
1570    var dates = $.fn.datepicker.dates = {
1571        en: {
1572            days: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"],
1573            daysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
1574            daysMin: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
1575            months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "
1575November", "December"],
1576            monthsShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
1577            today: "Today",
1578            clear: "Clear"
1579        }
1580    };
1581
1582    var DPGlobal = {
1583        modes: [
1584            {
1585                clsName: 'days',
1586                navFnc: 'Month',
1587                navStep: 1
1588            },
1589            {
1590                clsName: 'months',
1591                navFnc: 'FullYear',
1592                navStep: 1
1593            },
1594            {
1595                clsName: 'years',
1596                navFnc: 'FullYear',
1597                navStep: 10
1598            }],
1599        isLeapYear: function (year) {
1600            return (((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0));
1601        },
1602        getDaysInMonth: function (year, month) {
1603            return [31, (DPGlobal.isLeapYear(year) ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month];
1604        },
1605        validParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,
1606        nonpunctuation: /[^ -\/:-@\[\u3400-\u9fff-`{-~\t\n\r]+/g,
1607        parseFormat: function (format) {
1608            // IE treats \0 as a string end in inputs (truncating the value),
1609            // so it's a bad format delimiter, anyway
1610            var separators = format.replace(this.validParts, '\0').split('\0'),
1611                parts = format.match(this.validParts);
1612            if (!separators || !separators.length || !parts || parts.length === 0) {
1613                throw new Error("Invalid date format.");
1614            }
1615            return { separators: separators, parts: parts };
1616        },
1617        parseDate: function (date, format, language) {
1618            if (!date)
1619                return undefined;
1620            if (date instanceof Date)
1621                return date;
1622            if (typeof format === 'string')
1623                format = DPGlobal.parseFormat(format);
1624            var part_re = /([\-+]\d+)([dmwy])/,
1625                parts = date.match(/([\-+]\d+)([dmwy])/g),
1626                part, dir, i;
1627            if (/^[\-+]\d+[dmwy]([\s,]+[\-+]\d+[dmwy])*$/.test(date)) {
1628                date = new Date();
1629                for (i = 0; i < parts.length; i++) {
1630                    part = part_re.exec(parts[i]);
1631                    dir = parseInt(part[1]);
1632                    switch (part[2]) {
1633                        case 'd':
1634                            date.setUTCDate(date.getUTCDate() + dir);
1635                            break;
1636                        case 'm':
1637                            date = Datepicker.prototype.moveMonth.call(Datepicker.prototype, date, dir);
1638                            break;
1639                        case 'w':
1640                            date.setUTCDate(date.getUTCDate() + dir * 7);
1641                            break;
1642                        case 'y':
1643                            date = Datepicker.prototype.moveYear.call(Datepicker.prototype, date, dir);
1644                            break;
1645                    }
1646                }
1647                return UTCDate(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0);
1648            }
1649            parts = date && date.match(this.nonpunctuation) || [];
1650            date = new Date();
1651            var parsed = {},
1652                setters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],
1653                setters_map = {
1654                    yyyy: function (d, v) {
1655                        return d.setUTCFullYear(v);
1656                    },
1657                    yy: function (d, v) {
1658                        return d.setUTCFullYear(2000 + v);
1659                    },
1660                    m: function (d, v) {
1661                        if (isNaN(d))
1662                            return d;
1663                        v -= 1;
1664                        while (v < 0) v += 12;
1665                        v %= 12;
1666                        d.setUTCMonth(v);
1667                        while (d.getUTCMonth() !== v)
1668                            d.setUTCDate(d.getUTCDate() - 1);
1669                        return d;
1670                    },
1671                    d: function (d, v) {
1672                        return d.setUTCDate(v);
1673                    }
1674                },
1675                val, filtered;
1676            setters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];
1677            setters_map['dd'] = setters_map['d'];
1678            date = UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
1679            var fparts = format.parts.slice();
1680            // Remove noop parts
1681            if (parts.length !== fparts.length) {
1682                fparts = $(fparts).filter(function (i, p) {
1683                    return $.inArray(p, setters_order) !== -1;
1684                }).toArray();
1685            }
1686            // Process remainder
1687            function match_part() {
1688                var m = this.slice(0, parts[i].length),
1689                    p = parts[i].slice(0, m.length);
1690                return m.toLowerCase() === p.toLowerCase();
1691            }
1692            if (parts.length === fparts.length) {
1693                var cnt;
1694                for (i = 0, cnt = fparts.length; i < cnt; i++) {
1695                    val = parseInt(parts[i], 10);
1696                    part = fparts[i];
vendor: 4,131 bytes, lines 1697-1809
1697                    if (isNaN(val)) {
1698                        switch (part) {
1699                            case 'MM':
1700                                filtered = $(dates[language].months).filter(match_part);
1701                                val = $.inArray(filtered[0], dates[language].months) + 1;
1702                                break;
1703                            case 'M':
1704                                filtered = $(dates[language].monthsShort).filter(match_part);
1705                                val = $.inArray(filtered[0], dates[language].monthsShort) + 1;
1706                                break;
1707                        }
1708                    }
1709                    parsed[part] = val;
1710                }
1711                var _date, s;
1712                for (i = 0; i < setters_order.length; i++) {
1713                    s = setters_order[i];
1714                    if (s in parsed && !isNaN(parsed[s])) {
1715                        _date = new Date(date);
1716                        setters_map[s](_date, parsed[s]);
1717                        if (!isNaN(_date))
1718                            date = _date;
1719                    }
1720                }
1721            }
1722            return date;
1723        },
1724        formatDate: function (date, format, language) {
1725            if (!date)
1726                return '';
1727            if (typeof format === 'string')
1728                format = DPGlobal.parseFormat(format);
1729            var val = {
1730                d: date.getUTCDate(),
1731                D: dates[language].daysShort[date.getUTCDay()],
1732                DD: dates[language].days[date.getUTCDay()],
1733                m: date.getUTCMonth() + 1,
1734                M: dates[language].monthsShort[date.getUTCMonth()],
1735                MM: dates[language].months[date.getUTCMonth()],
1736                yy: date.getUTCFullYear().toString().substring(2),
1737                yyyy: date.getUTCFullYear()
1738            };
1739            val.dd = (val.d < 10 ? '0' : '') + val.d;
1740            val.mm = (val.m < 10 ? '0' : '') + val.m;
1741            date = [];
1742            var seps = $.extend([], format.separators);
1743            for (var i = 0, cnt = format.parts.length; i <= cnt; i++) {
1744                if (seps.length)
1745                    date.push(seps.shift());
1746                date.push(val[format.parts[i]]);
1747            }
1748            return date.join('');
1749        },
1750        headTemplate: '<thead>' +
1751            '<tr>' +
1752            '<th class="prev">&#171;</th>' +
1753            '<th colspan="5" class="datepicker-switch"></th>' +
1754            '<th class="next">&#187;</th>' +
1755            '</tr>' +
1756            '</thead>',
1757        contTemplate: '<tbody><tr><td colspan="7"></td></tr></tbody>',
1758        footTemplate: '<tfoot>' +
1759            '<tr>' +
1760            '<th colspan="7" class="today"></th>' +
1761            '</tr>' +
1762            '<tr>' +
1763            '<th colspan="7" class="clear"></th>' +
1764            '</tr>' +
1765            '</tfoot>'
1766    };
1767    DPGlobal.template = '<div class="datepicker">' +
1768        '<div class="datepicker-days">' +
1769        '<table class=" table-condensed">' +
1770        DPGlobal.headTemplate +
1771        '<tbody></tbody>' +
1772        DPGlobal.footTemplate +
1773        '</table>' +
1774        '</div>' +
1775        '<div class="datepicker-months">' +
1776        '<table class="table-condensed">' +
1777        DPGlobal.headTemplate +
1778        DPGlobal.contTemplate +
1779        DPGlobal.footTemplate +
1780        '</table>' +
1781        '</div>' +
1782        '<div class="datepicker-years">' +
1783        '<table class="table-condensed">' +
1784        DPGlobal.headTemplate +
1785        DPGlobal.contTemplate +
1786        DPGlobal.footTemplate +
1787        '</table>' +
1788        '</div>' +
1789        '</div>';
1790
1791    $.fn.datepicker.DPGlobal = DPGlobal;
1792
1793
1794    /* DATEPICKER NO CONFLICT
1795    * =================== */
1796
1797    $.fn.datepicker.noConflict = function () {
1798        $.fn.datepicker = old;
1799        return this;
1800    };
1801
1802    /* DATEPICKER VERSION
1803     * =================== */
1804    $.fn.datepicker.version = "1.5.0";
1805
1806    /* DATEPICKER DATA-API
1807    * ================== */
1808
1809    $(document).on(
1810        'focus.datepicker.data-api click.datepicker.data-api',
1811        '[data-provide="datepicker"]',
1812        function (e) {
1813            var $this = $(this);
1814            if ($this.data('datepicker'))
1815                return;
1816            e.preventDefault();
1817            // component click requires us to explicitly show it
1818            datepickerPlugin.call($this, 'show');
1819        }
1820    );
1821    $(function () {
1822        datepickerPlugin.call($('[data-provide="datepicker-inline"]'));
1823    });
1824
1825}(window.jQuery));
1826
1827var startDate = new Date('01/01/2016');
1828var FromEndDate = new Date();
1829var groupName;
1830var srcDate;
1831if (jQuery('.datepicker').length > 0) {
1832    if (jQuery('.datepicker').filter('input[mindate]').length === 0) {
1833
1834        jQuery('.datepicker').datepicker().on('changeMonth',
1835            function (event) {
1836                isSelectCalender = true;
1837            }).on('changeDate', function () {
1838                isSelectCalender = true;
1839            }).on('changeYear', function () {
1840                isSelectCalender = true;
1841            }).on('changeDecade', function () {
1842                isSelectCalender = true;
1843            }).on('changeCentury', function () {
1844                isSelectCalender = true;
1845            }).on('show', function () {
1846                isSelectCalender = true;
1847            }).on('clearDate', function () {
1848                isSelectCalender = true;
1849            });
1850    }
1851    else {
1852        jQuery('.datepicker').filter('input[mindate]').datepicker({
1853            weekStart: 1,
1854            autoclose: true
1855        }).on('changeDate', function (selected) {
1856            startDate = new Date(selected.date.valueOf());
1857            startDate.setDate(startDate.getDate(new Date(selected.date.valueOf())));
1858            groupName = $(this).attr('group');
1859            $('.datepicker').filter('input[group=' + groupName + ']').filter('input[maxdate]').datepicker('setStartDate', startDate);
1860        }).on('show', function (ev) {
1861            if ($(this).attr('mindate') !== undefined && $(this).attr('mindate') !== "") {
1862                srcDate = $(this).attr('mindate').replace(/-/g, ' ');
1863                var mindate = new Date(srcDate);
1864                $(this).datepicker('setStartDate', mindate);
1865            }
1866            groupName = $(this).attr('group');
1867            if (this.s == null) return '';
1868            if (groupName !== undefined && groupName !== "")
1869                srcDate = $('.datepicker').filter('input[group=' + groupName + ']').filter('input[maxdate]').val().replace(/-/g, ' ');
1870
1871            if (srcDate !== "" && srcDate !== undefined) {
1872                startDate = new Date(srcDate);
1873                startDate.setDate(startDate.getDate(new Date(srcDate)));
1874                $(this).datepicker('setEndDate', startDate);
1875            }
1876
1877            if ($(this).attr('maxdate') !== undefined && $(this).attr('maxdate') !== "") {
1878                srcDate = $(this).attr('maxdate').replace(/-/g, ' ');
1879                var maxdate = new Date(srcDate);
1880                $(this).datepicker('setEndDate', maxdate);
1881            }
1882        });
1883
1884        jQuery('.datepicker').filter('input[maxdate]').datepicker({
1885            weekStart: 1,
1886            autoclose: true
1887        }).on('changeDate', function (selected) {
1888            //srcDate = selected.date.valueOf().replace(/-/g, ' ');
1889            FromEndDate = new Date(selected.date.valueOf());
1890            FromEndDate.setDate(FromEndDate.getDate(new Date(selected.date.valueOf())));
1891            groupName = $(this).attr('group');
1892            $('.datepicker').filter('input[group=' + groupName + ']').filter('input[mindate]').datepicker('setEndDate', FromEndDate);
1893        }).on('show', function (ev) {
1894            groupName = $(this).attr('group');
1895            srcDate = $('.datepicker').filter('input[group=' + groupName + ']').filter('input[mindate]').val().replace(/-/g, ' ');
1896            startDate = new Date(srcDate);
1897            startDate.setDate(startDate.getDate(new Date(srcDate)));
1898
1899            $('.datepicker').filter('input[group=' + groupName + ']').filter('input[maxdate]').datepicker('setStartDate', startDate);
1900
1901            if ($(this).attr('mindate') !== undefined && $(this).attr('mindate') !== "") {
1902                srcDate = $(this).attr('mindate').replace(/-/g, ' ');
1903                var mindate = new Date($(this).attr('mindate'));
1904                $(this).datepicker('setStartDate', mindate);
1905            }
1906
1907            if ($(this).attr('maxdate') !== undefined && $(this).attr('maxdate') !== "") {
1908                srcDate = $(this).attr('maxdate').replace(/-/g, ' ');
1909                var maxdate = new Date($(this).attr('maxdate'));
1910                $(this).datepicker('setEndDate', maxdate);
1911            }
1912        });
1913    }
1914}
1915
1916//To show time format popup on click of start and expire time input box.
1917$("#StartTime, #ExpireTime").on("click", function () {
1918    $(".bootstrap-datetimepicker-widget").css("display", "block");
1919});
1920jQuery('.datepicker').attr("readonly", "readonly");

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.