PageSourceSearch

https://sibgenco.ru/local/templates/new_sibgenco/js/daterangepicker/jquery.daterangepicker.min.js

js sibgenco.ru collected 2026-10-02 16:42:58 UTC 74,214 bytes, 1,813 lines download raw bytes

1// jquery.daterangepicker.js
2// author : Chunlong Liu
3// license : MIT
4// www.jszen.com
5
6(function(factory) {
7    if (typeof define === 'function' && define.amd) {
8        // AMD. Register as an anonymous module.
9        define(['jquery', 'moment'], factory);
10    } else if (typeof exports === 'object' && typeof module !== 'undefined') {
11        // CommonJS. Register as a module
12        module.exports = factory(require('jquery'), require('moment'));
13    } else {
14        // Browser globals
15        factory(jQuery, moment);
16    }
17}(function($, moment) {
18    'use strict';
19    $.dateRangePickerLanguages = {
20        "default": //default language: English
21        {
22            "selected": "Selected:",
23            "day": "Day",
24            "days": "Days",
25            "apply": "Close",
26            "week-1": "mo",
27            "week-2": "tu",
28            "week-3": "we",
29            "week-4": "th",
30            "week-5": "fr",
31            "week-6": "sa",
32            "week-7": "su",
33            "week-number": "W",
34            "month-name": ["january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"],
35            "shortcuts": "Shortcuts",
36            "custom-values": "Custom Values",
37            "past": "Past",
38            "following": "Following",
39            "previous": "Previous",
40            "prev-week": "Week",
41            "prev-month": "Month",
42            "prev-year": "Year",
43            "next": "Next",
44            "next-week": "Week",
45            "next-month": "Month",
46            "next-year": "Year",
47            "less-than": "Date range should not be more than %d days",
48            "more-than": "Date range should not be less than %d days",
49            "default-more": "Please select a date range longer than %d days",
50            "default-single": "Please select a date",
51            "default-less": "Please select a date range less than %d days",
52            "default-range": "Please select a date range between %d and %d days",
53            "default-default": "Please select a date range",
54            "time": "Time",
55            "hour": "Hour",
56            "minute": "Minute"
57        },
58        "ru": {
59            "selected": "Выбрано:",
60            "day": "День",
61            "days": "Дней",
62            "apply": "Применить",
63            "week-1": "пн",
64            "week-2": "вт",
65            "week-3": "ср",
66            "week-4": "чт",
67            "week-5": "пт",
68            "week-6": "сб",
69            "week-7": "вс",
70            "month-name": ["январь", "февраль", "март", "апрель", "май", "июнь", "июль", "август", "сентябрь", "октябрь", "ноябрь", "декабрь"],
71            "shortcuts": "Быстрый выбор",
72            "custom-values": "Пользовательские значения",
73            "past": "Прошедшие",
74            "following": "Следующие",
75            "previous": "   ",
76            "prev-week": "Неделя",
77            "prev-month": "Месяц",
78            "prev-year": "Год",
79            "next": "   ",
80            "next-week": "Неделя",
81            "next-month": "Месяц",
82            "next-year": "Год",
83            "less-than": "Диапазон не может быть больше %d дней",
84            "more-than": "Диапазон не может быть меньше %d дней",
85            "default-more": "Пожалуйста выберите диапазон больше %d дней",
86            "default-single": "Пожалуйста выберите дату",
87            "default-less": "Пожалуйста выберите диапазон меньше %d дней",
88            "default-range": "Пожалуйста выберите диапазон между %d и %d днями",
89            "default-default": "Пожалуйста выберите диапазон",
90            "time": "Время",
91            "hour": "Часы",
92            "minute": "Минуты"
93        }
94    };
95
96    $.fn.dateRangePicker = function(opt) {
97        if (!opt) opt = {};
98        opt = $.extend(true, {
99            autoClose: false,
100            format: 'YYYY-MM-DD',
101            separator: ' to ',
102            language: 'auto',
103            startOfWeek: 'sunday', // or monday
104            getValue: function() {
105                return $(this).val();
106            },
107            setValue: function(s) {
108                if (!$(this).attr('readonly') && !$(this).is(':disabled') && s != $(this).val()) {
109                    $(this).val(s);
110                }
111            },
112            startDate: false,
113            endDate: false,
114            time: {
115                enabled: false
116            },
117            minDays: 0,
118            maxDays: 0,
119            showShortcuts: false,
120            shortcuts: {
121                //'prev-days': [1,3,5,7],
122                // 'next-days': [3,5,7],
123                //'prev' : ['week','month','year'],
124                // 'next' : ['week','month','year']
125            },
126            customShortcuts: [],
127            inline: false,
128            container: 'body',
129            alwaysOpen: false,
130            singleDate: false,
131            lookBehind: false,
132            batchMode: false,
133            duration: 200,
134            stickyMonths: false,
135            dayDivAttrs: [],
136            dayTdAttrs: [],
137            selectForward: false,
138            selectBackward: false,
139            applyBtnClass: '',
140            singleMonth: 'auto',
141            hoveringTooltip: function(days, startTime, hoveringTime) {
142                return days > 1 ? days + ' ' + translate('days') : '';
143            },
144            showTopbar: true,
145            swapTime: false,
146            showWeekNumbers: false,
147            getWeekNumber: function(date) //date will be the first day of a week
148            {
149                return moment(date).format('w');
150            },
151            customOpenAnimation: null,
152            customCloseAnimation: null,
153            customArrowPrevSymbol: null,
154            customArrowNextSymbol: null,
155            monthSelect: false,
156            yearSelect: false
157        }, opt);
158
159        opt.start = false;
160        opt.end = false;
161
162        opt.startWeek = false;
163
164        //detect a touch device
165        opt.isTouchDevice = 'ontouchstart' in window || navigator.msMaxTouchPoints;
166
167        //if it is a touch device, hide hovering tooltip
168        if (opt.isTouchDevice) opt.hoveringTooltip = false;
169
170        //show one month on mobile devices
171        if (opt.singleMonth == 'auto') opt.singleMonth = $(window).width() < 480;
172        if (opt.singleMonth) opt.stickyMonths = false;
173
174        if (!opt.showTopbar) opt.autoClose = true;
175
176        if (opt.startDate && typeof opt.startDate == 'string') opt.startDate = moment(opt.startDate, opt.format).toDate();
177        if (opt.endDate && typeof opt.endDate == 'string') opt.endDate = moment(opt.endDate, opt.format).toDate();
178
179        if (opt.yearSelect && typeof opt.yearSelect === 'boolean') {
180            opt.yearSelect = function(current) { return [current - 5, current + 5]; }
181        }
182
183        var languages = getLanguages();
184        var box;
185        var initiated = false;
186        var self = this;
187        var selfDom = $(self).get(0);
188        var domChangeTimer;
189
190        $(this).off('.datepicker').on('click.datepicker', function(evt) {
191            var isOpen = box.is(':visible');
192            if (!isOpen) open(opt.duration);
193        }).on('change.datepicker', function(evt) {
194            checkAndSetDefaultValue();
195        }).on('keyup.datepicker', function() {
196            try {
197                clearTimeout(domChangeTimer);
198            } catch (e) {}
199            domChangeTimer = setTimeout(function() {
200                checkAndSetDefaultValue();
201            }, 2000);
202        });
203
204        init_datepicker.call(this);
205
206        if (opt.alwaysOpen) {
207            open(0);
208        }
209
210        // expose some api
211        $(this).data('dateRangePicker', {
212            setStart: function(d1) {
213                if (typeof d1 == 'string') {
214                    d1 = moment(d1, opt.format).toDate();
215                }
216
217                opt.end = false;
218                setSingleDate(d1);
219
220                return this;
221            },
222            setEnd: function(d2, silent) {
223                var start = new Date();
224                start.setTime(opt.start);
225                if (typeof d2 == 'string') {
226                    d2 = moment(d2, opt.format).toDate();
227                }
228                setDateRange(start, d2, silent);
229                return this;
230            },
231            setDateRange: function(d1, d2, silent) {
232                if (typeof d1 == 'string' && typeof d2 == 'string') {
233                    d1 = moment(d1, opt.format).toDate();
234                    d2 = moment(d2, opt.format).toDate();
235                }
236                setDateRange(d1, d2, silent);
237            },
238            clear: clearSelection,
239            close: closeDatePicker,
240            open: open,
241            redraw: redrawDatePicker,
242            getDatePicker: getDatePicker,
243            resetMonthsView: resetMonthsView,
244            destroy: function() {
245                $(self).off('.datepicker');
246                $(self).data('dateRangePicker', '');
247                $(self).data('date-picker-opened', null);
248                box.remove();
249                $(window).off('resize.datepicker', calcPosition);
250                $(document).off('click.datepicker', outsideClickClose);
251            }
252        });
253
254        $(window).on('resize.datepicker', calcPosition);
255
256        return this;
257
258        function IsOwnDatePickerClicked(evt, selfObj) {
259            return (selfObj.contains(evt.target) || evt.target == selfObj || (selfObj.childNodes != undefined && $.inArray(evt.target, selfObj.childNodes) >= 0));
260        }
261
262        function init_datepicker() {
263            var self = this;
264
265            if ($(this).data('date-picker-opened')) {
266                closeDatePicker();
267                return;
268            }
269            $(this).data('date-picker-opened', true);
270
271
272            box = createDom().hide();
273            box.append('<div class="date-range-length-tip"></div>');
274
275            $(opt.container).append(box);
276
277            if (!opt.inline) {
278                calcPosition();
279            } else {
280                box.addClass('inline-wrapper');
281            }
282
283            if (opt.alwaysOpen) {
284                box.find('.apply-btn').hide();
285            }
286
287            var defaultTime = getDefaultTime();
288            resetMonthsView(defaultTime);
289
290            if (opt.time.enabled) {
291                if ((opt.startDate && opt.endDate) || (opt.start && opt.end)) {
292                    showTime(moment(opt.start || opt.startDate).toDate(), 'time1');
293                    showTime(moment(opt.end || opt.endDate).toDate(), 'time2');
294                } else {
295                    var defaultEndTime = opt.defaultEndTime ? opt.defaultEndTime : defaultTime;
296                    showTime(defaultTime, 'time1');
297                    showTime(defaultEndTime, 'time2');
298                }
299            }
300
301            //showSelectedInfo();
302
303
304            var defaultTopText = '';
305            if (opt.singleDate)
306                defaultTopText = translate('default-single');
307            else if (opt.minDays && opt.maxDays)
308                defaultTopText = translate('default-range');
309            else if (opt.minDays)
310                defaultTopText = translate('default-more');
311            else if (opt.maxDays)
312                defaultTopText = translate('default-less');
313            else
314                defaultTopText = translate('default-default');
315
316            box.find('.default-top').html(defaultTopText.replace(/\%d/, opt.minDays).replace(/\%d/, opt.maxDays));
317            if (opt.singleMonth) {
318                box.addClass('single-month');
319            } else {
320                box.addClass('two-months');
321            }
322
323
324            setTimeout(function() {
325                updateCalendarWidth();
326                initiated = true;
327            }, 0);
328
329            box.click(function(evt) {
330                evt.stopPropagation();
331            });
332
333            //if user click other place of the webpage, close date range picker window
334            $(document).on('click.datepicker', outsideClickClose);
335
336            box.find('.next').click(function() {
337                if (!opt.stickyMonths)
338                    gotoNextMonth(this);
339                else
340                    gotoNextMonth_stickily(this);
341            });
342
343            function gotoNextMonth(self) {
344                var isMonth2 = $(self).parents('table').hasClass('month2');
345                var month = isMonth2 ? opt.month2 : opt.month1;
346                month = nextMonth(month);
347                if (!opt.singleMonth && !opt.singleDate && !isMonth2 && compare_month(month, opt.month2) >= 0 || isMonthOutOfBounds(month)) return;
348                showMonth(month, isMonth2 ? 'month2' : 'month1');
349                showGap();
350            }
351
352            function gotoNextMonth_stickily(self) {
353                var nextMonth1 = nextMonth(opt.month1);
354                var nextMonth2 = nextMonth(opt.month2);
355                if (isMonthOutOfBounds(nextMonth2)) return;
356                if (!opt.singleDate && compare_month(nextMonth1, nextMonth2) >= 0) return;
357                showMonth(nextMonth1, 'month1');
358                showMonth(nextMonth2, 'month2');
359                showSelectedDays();
360            }
361
362
363            box.find('.prev').click(function() {
364                if (!opt.stickyMonths)
365                    gotoPrevMonth(this);
366                else
367                    gotoPrevMonth_stickily(this);
368            });
369
370            function gotoPrevMonth(self) {
371                var isMonth2 = $(self).parents('table').hasClass('month2');
372                var month = isMonth2 ? opt.month2 : opt.month1;
373                month = prevMonth(month);
374                if (isMonth2 && compare_month(month, opt.month1) <= 0 || isMonthOutOfBounds(month)) return;
375                showMonth(month, isMonth2 ? 'month2' : 'month1');
376                showGap();
377            }
378
379            function gotoPrevMonth_stickily(self) {
380                var prevMonth1 = prevMonth(opt.month1);
381                var prevMonth2 = prevMonth(opt.month2);
382                if (isMonthOutOfBounds(prevMonth1)) return;
383                if (!opt.singleDate && compare_month(prevMonth2, prevMonth1) <= 0) return;
384                showMonth(prevMonth2, 'month2');
385                showMonth(prevMonth1, 'month1');
386                showSelectedDays();
387            }
388
389            box.attr('unselectable', 'on')
390                .css('user-select', 'none')
391                .on('selectstart', function(e) {
392                    e.preventDefault();
393                    return false;
394                });
395
396            box.find('.apply-btn').click(function() {
397                closeDatePicker();
398                var dateRange = getDateString(new Date(opt.start)) + opt.separator + getDateString(new Date(opt.end));
399                $(self).trigger('datepicker-apply', {
400                    'value': dateRange,
401                    'date1': new Date(opt.start),
402                    'date2': new Date(opt.end)
403                });
404            });
405
406            box.find('[custom]').click(function() {
407                var valueName = $(this).attr('custom');
408                opt.start = false;
409                opt.end = false;
410                box.find('.day.checked').removeClass('checked');
411                opt.setValue.call(selfDom, valueName);
412                checkSelectionValid();
413                showSelectedInfo(true);
414                showSelectedDays();
415                if (opt.autoClose) closeDatePicker();
416            });
417
418            box.find('[shortcut]').click(function() {
419                var shortcut = $(this).attr('shortcut');
420                var end = new Date(),
421                    start = false;
422                var dir;
423                if (shortcut.indexOf('day') != -1) {
424                    var day = parseInt(shortcut.split(',', 2)[1], 10);
425                    start = new Date(new Date().getTime() + 86400000 * day);
426                    end = new Date(end.getTime() + 86400000 * (day > 0 ? 1 : -1));
427                } else if (shortcut.indexOf('week') != -1) {
428                    dir = shortcut.indexOf('prev,') != -1 ? -1 : 1;
429                    var stopDay;
430                    if (dir == 1)
431                        stopDay = opt.startOfWeek == 'monday' ? 1 : 0;
432                    else
433                        stopDay = opt.startOfWeek == 'monday' ? 0 : 6;
434
435                    end = new Date(end.getTime() - 86400000);
436                    while (end.getDay() != stopDay) end = new Date(end.getTime() + dir * 86400000);
437                    start = new Date(end.getTime() + dir * 86400000 * 6);
438                } else if (shortcut.indexOf('month') != -1) {
439                    dir = shortcut.indexOf('prev,') != -1 ? -1 : 1;
440                    if (dir == 1)
441                        start = nextMonth(end);
442                    else
443                        start = prevMonth(end);
444                    start.setDate(1);
445                    end = nextMonth(start);
446                    end.setDate(1);
447                    end = new Date(end.getTime() - 86400000);
448                } else if (shortcut.indexOf('year') != -1) {
449                    dir = shortcut.indexOf('prev,') != -1 ? -1 : 1;
450                    start = new Date();
451                    start.setFullYear(end.getFullYear() + dir);
452                    start.setMonth(0);
453                    start.setDate(1);
454                    end.setFullYear(end.getFullYear() + dir);
455                    end.setMonth(11);
456                    end.setDate(31);
457                } else if (shortcut == 'custom') {
458                    var name = $(this).html();
459                    if (opt.customShortcuts && opt.customShortcuts.length > 0) {
460                        for (var i = 0; i < opt.customShortcuts.length; i++) {
461                            var sh = opt.customShortcuts[i];
462                            if (sh.name == name) {
463                                var data = [];
464                                // try
465                                // {
466                                data = sh['dates'].call();
467                                //}catch(e){}
468                                if (data && data.length == 2) {
469                                    start = data[0];
470                                    end = data[1];
471                                }
472
473                                // if only one date is specified then just move calendars there
474                                // move calendars to show this date's month and next months
475                                if (data && data.length == 1) {
476                                    var movetodate = data[0];
477                                    showMonth(movetodate, 'month1');
478                                    showMonth(nextMonth(movetodate), 'month2');
479                                    showGap();
480                                }
481
482                                break;
483                            }
484                        }
485                    }
486                }
487                if (start && end) {
488                    setDateRange(start, end);
489                    checkSelectionValid();
490                }
491            });
492
493            box.find('.time1 input[type=range]').on('change touchmove', function(e) {
494                var target = e.target,
495                    hour = target.name == 'hour' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined,
496                    min = target.name == 'minute' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined;
497                setTime('time1', hour, min);
498            });
499
500            box.find('.time2 input[type=range]').on('change touchmove', function(e) {
501                var target = e.target,
502                    hour = target.name == 'hour' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined,
503                    min = target.name == 'minute' ? $(target).val().replace(/^(\d{1})$/, '0$1') : undefined;
504                setTime('time2', hour, min);
505            });
506
507        }
508
509
510        function calcPosition() {
511            if (!opt.inline) {
512                var offset = $(self).offset();
513                if ($(opt.container).css('position') == 'relative') {
514                    var containerOffset = $(opt.container).offset();
515                    var leftIndent = Math.max(0, offset.left + box.outerWidth() - $('body').width() + 16);
516                    box.css({
517                        top: offset.top - containerOffset.top + $(self).outerHeight() + 4,
518                        left: offset.left - containerOffset.left - leftIndent
519                    });
520                } else {
521                    if (offset.left < 460) //left to right
522                    {
523                        box.css({
524                            top: offset.top + $(self).outerHeight() + parseInt($('body').css('border-top') || 0, 10),
525                            left: offset.left
526                        });
527                    } else {
528                        box.css({
529                            top: offset.top + $(self).outerHeight() + parseInt($('body').css('border-top') || 0, 10),
530                            left: offset.left + $(self).width() - box.width() - 16
531                        });
532                    }
533                }
534            }
535        }
536
537        // Return the date picker wrapper element
538        function getDatePicker() {
539            return box;
540        }
541
542        function open(animationTime) {
543            redrawDatePicker();
544            checkAndSetDefaultValue();
545            if (opt.customOpenAnimation) {
546                opt.customOpenAnimation.call(box.get(0), function() {
547                    $(self).trigger('datepicker-opened', {
548                        relatedTarget: box
549                    });
550                });
551            } else {
552                box.slideDown(animationTime, function() {
553                    $(self).trigger('datepicker-opened', {
554                        relatedTarget: box
555                    });
556                });
557            }
558            $(self).trigger('datepicker-open', {
559                relatedTarget: box
560            });
561            showGap();
562            updateCalendarWidth();
563            calcPosition();
564        }
565
566        function checkAndSetDefaultValue() {
567            var __default_string = opt.getValue.call(selfDom);
568            var defaults = __default_string ? __default_string.split(opt.separator) : '';
569
570            if (defaults && ((defaults.length == 1 && opt.singleDate) || defaults.length >= 2)) {
571                var ___format = opt.format;
572                if (___format.match(/Do/)) {
573
574                    ___format = ___format.replace(/Do/, 'D');
575                    defaults[0] = defaults[0].replace(/(\d+)(th|nd|st)/, '$1');
576                    if (defaults.length >= 2) {
577                        defaults[1] = defaults[1].replace(/(\d+)(th|nd|st)/, '$1');
578                    }
579                }
580                // set initiated  to avoid triggerring datepicker-change event
581                initiated = false;
582                if (defaults.length >= 2) {
583                    setDateRange(getValidValue(defaults[0], ___format, moment.locale(opt.language)), getValidValue(defaults[1], ___format, moment.locale(opt.language)));
584                } else if (defaults.length == 1 && opt.singleDate) {
585                    setSingleDate(getValidValue(defaults[0], ___format, moment.locale(opt.language)));
586                }
587
588                initiated = true;
589            }
590        }
591
592        function getValidValue(date, format, locale) {
593            if (moment(date, format, locale).isValid()) {
594                return moment(date, format, locale).toDate();
595            } else {
596                return moment().toDate();
597            }
598        }
599
600        function updateCalendarWidth() {
601            var gapMargin = box.find('.gap').css('margin-left');
602            if (gapMargin) gapMargin = parseInt(gapMargin);
603            var w1 = box.find('.month1').width();
604            var w2 = box.find('.gap').width() + (gapMargin ? gapMargin * 2 : 0);
605            var w3 = box.find('.month2').width();
606            box.find('.month-wrapper').width(w1 + w2 + w3);
607        }
608
609        function renderTime(name, date) {
610            box.find('.' + name + ' input[type=range].hour-range').val(moment(date).hours());
611            box.find('.' + name + ' input[type=range].minute-range').val(moment(date).minutes());
612            setTime(name, moment(date).format('HH'), moment(date).format('mm'));
613        }
614
615        function changeTime(name, date) {
616            opt[name] = parseInt(
617                moment(parseInt(date))
618                .startOf('day')
619                .add(moment(opt[name + 'Time']).format('HH'), 'h')
620                .add(moment(opt[name + 'Time']).format('mm'), 'm').valueOf()
621            );
622        }
623
624        function swapTime() {
625            renderTime('time1', opt.start);
626            renderTime('time2', opt.end);
627        }
628
629        function setTime(name, hour, minute) {
630            hour && (box.find('.' + name + ' .hour-val').text(hour));
631            minute && (box.find('.' + name + ' .minute-val').text(minute));
632            switch (name) {
633                case 'time1':
634                    if (opt.start) {
635                        setRange('start', moment(opt.start));
636                    }
637                    setRange('startTime', moment(opt.startTime || moment().valueOf()));
638                    break;
639                case 'time2':
640                    if (opt.end) {
641                        setRange('end', moment(opt.end));
642                    }
643                    setRange('endTime', moment(opt.endTime || moment().valueOf()));
644                    break;
645            }
646
647            function setRange(name, timePoint) {
648                var h = timePoint.format('HH'),
649                    m = timePoint.format('mm');
650                opt[name] = timePoint
651                    .startOf('day')
652                    .add(hour || h, 'h')
653                    .add(minute || m, 'm')
654                    .valueOf();
655            }
656            checkSelectionValid();
657            showSelectedInfo();
658            showSelectedDays();
659        }
660
661        function clearSelection() {
662            opt.start = false;
663            opt.end = false;
664            box.find('.day.checked').removeClass('checked');
665            box.find('.day.last-date-selected').removeClass('last-date-selected');
666            box.find('.day.first-date-selected').removeClass('first-date-selected');
667            opt.setValue.call(selfDom, '');
668            checkSelectionValid();
669            showSelectedInfo();
670            showSelectedDays();
671        }
672
673        function handleStart(time) {
674            var r = time;
675            if (opt.batchMode === 'week-range') {
676                if (opt.startOfWeek === 'monday') {
677                    r = moment(parseInt(time)).startOf('isoweek').valueOf();
678                } else {
679                    r = moment(parseInt(time)).startOf('week').valueOf();
680                }
681            } else if (opt.batchMode === 'month-range') {
682                r = moment(parseInt(time)).startOf('month').valueOf();
683            }
684            return r;
685        }
686
687        function handleEnd(time) {
688            var r = time;
689            if (opt.batchMode === 'week-range') {
690                if (opt.startOfWeek === 'monday') {
691                    r = moment(parseInt(time)).endOf('isoweek').valueOf();
692                } else {
693                    r = moment(parseInt(time)).endOf('week').valueOf();
694                }
695            } else if (opt.batchMode === 'month-range') {
696                r = moment(parseInt(time)).endOf('month').valueOf();
697            }
698            return r;
699        }
700
701
702        function dayClicked(day) {
703            if (day.hasClass('invalid')) return;
704            var time = day.attr('time');
705            day.addClass('checked');
706            if (opt.singleDate) {
707                opt.start = time;
708                opt.end = false;
709            } else if (opt.batchMode === 'week') {
710                if (opt.startOfWeek === 'monday') {
711                    opt.start = moment(parseInt(time)).startOf('isoweek').valueOf();
712                    opt.end = moment(parseInt(time)).endOf('isoweek').valueOf();
713                } else {
714                    opt.end = moment(parseInt(time)).endOf('week').valueOf();
715                    opt.start = moment(parseInt(time)).startOf('week').valueOf();
716                }
717            } else if (opt.batchMode === 'workweek') {
718                opt.start = moment(parseInt(time)).day(1).valueOf();
719                opt.end = moment(parseInt(time)).day(5).valueOf();
720            } else if (opt.batchMode === 'weekend') {
721                opt.start = moment(parseInt(time)).day(6).valueOf();
722                opt.end = moment(parseInt(time)).day(7).valueOf();
723            } else if (opt.batchMode === 'month') {
724                opt.start = moment(parseInt(time)).startOf('month').valueOf();
725                opt.end = moment(parseInt(time)).endOf('month').valueOf();
726            } else if ((opt.start && opt.end) || (!opt.start && !opt.end)) {
727                opt.start = handleStart(time);
728                opt.end = false;
729            } else if (opt.start) {
730                opt.end = handleEnd(time);
731                if (opt.time.enabled) {
732                    changeTime('end', opt.end);
733                }
734            }
735
736            //Update time in case it is enabled and timestamps are available
737            if (opt.time.enabled) {
738                if (opt.start) {
739                    changeTime('start', opt.start);
740                }
741                if (opt.end) {
742                    changeTime('end', opt.end);
743                }
744            }
745
746            //In case the start is after the end, swap the timestamps
747            if (!opt.singleDate && opt.start && opt.end && opt.start > opt.end) {
748                var tmp = opt.end;
749                opt.end = handleEnd(opt.start);
750                opt.start = handleStart(tmp);
751                if (opt.time.enabled && opt.swapTime) {
752                    swapTime();
753                }
754            }
755
756            opt.start = parseInt(opt.start);
757            opt.end = parseInt(opt.end);
758
759            clearHovering();
760            if (opt.start && !opt.end) {
761                $(self).trigger('datepicker-first-date-selected', {
762                    'date1': new Date(opt.start)
763                });
764                dayHovering(day);
765            }
766            updateSelectableRange(time);
767
768            checkSelectionValid();
769            showSelectedInfo();
770            showSelectedDays();
771            autoclose();
772        }
773
774
775        function weekNumberClicked(weekNumberDom) {
776            var thisTime = parseInt(weekNumberDom.attr('data-start-time'), 10);
777            var date1, date2;
778            if (!opt.startWeek) {
779                opt.startWeek = thisTime;
780                weekNumberDom.addClass('week-number-selected');
781                date1 = new Date(thisTime);
782                opt.start = moment(date1).day(opt.startOfWeek == 'monday' ? 1 : 0).valueOf();
783                opt.end = moment(date1).day(opt.startOfWeek == 'monday' ? 7 : 6).valueOf();
784            } else {
785                box.find('.week-number-selected').removeClass('week-number-selected');
786                date1 = new Date(thisTime < opt.startWeek ? thisTime : opt.startWeek);
787                date2 = new Date(thisTime < opt.startWeek ? opt.startWeek : thisTime);
788                opt.startWeek = false;
789                opt.start = moment(date1).day(opt.startOfWeek == 'monday' ? 1 : 0).valueOf();
790                opt.end = moment(date2).day(opt.startOfWeek == 'monday' ? 7 : 6).valueOf();
791            }
792            updateSelectableRange();
793            checkSelectionValid();
794            showSelectedInfo();
795            showSelectedDays();
796            autoclose();
797        }
798
799        function isValidTime(time) {
800            time = parseInt(time, 10);
801            if (opt.startDate && compare_day(time, opt.startDate) < 0) return false;
802            if (opt.endDate && compare_day(time, opt.endDate) > 0) return false;
803
804            if (opt.start && !opt.end && !opt.singleDate) {
805                //check maxDays and minDays setting
806                if (opt.maxDays > 0 && countDays(time, opt.start) > opt.maxDays) return false;
807                if (opt.minDays > 0 && countDays(time, opt.start) < opt.minDays) return false;
808
809                //check selectForward and selectBackward
810                if (opt.selectForward && time < opt.start) return false;
811                if (opt.selectBackward && time > opt.start) return false;
812
813                //check disabled days
814                if (opt.beforeShowDay && typeof opt.beforeShowDay == 'function') {
815                    var valid = true;
816                    var timeTmp = time;
817                    while (countDays(timeTmp, opt.start) > 1) {
818                        var arr = opt.beforeShowDay(new Date(timeTmp));
819                        if (!arr[0]) {
820                            valid = false;
821                            break;
822                        }
823                        if (Math.abs(timeTmp - opt.start) < 86400000) break;
824                        if (timeTmp > opt.start) timeTmp -= 86400000;
825                        if (timeTmp < opt.start) timeTmp += 86400000;
826                    }
827                    if (!valid) return false;
828                }
829            }
830            return true;
831        }
832
833
834        function updateSelectableRange() {
835            box.find('.day.invalid.tmp').removeClass('tmp invalid').addClass('valid');
836            if (opt.start && !opt.end) {
837                box.find('.day.toMonth.valid').each(function() {
838                    var time = parseInt($(this).attr('time'), 10);
839                    if (!isValidTime(time))
840                        $(this).addClass('invalid tmp').removeClass('valid');
841                    else
842                        $(this).addClass('valid tmp').removeClass('invalid');
843                });
844            }
845
846            return true;
847        }
848
849
850        function dayHovering(day) {
851            var hoverTime = parseInt(day.attr('time'));
852            var tooltip = '';
853
854            if (day.hasClass('has-tooltip') && day.attr('data-tooltip')) {
855                tooltip = '<span class="tooltip-content">' + day.attr('data-tooltip') + '</span>';
856            } else if (!day.hasClass('invalid')) {
857                if (opt.singleDate) {
858                    box.find('.day.hovering').removeClass('hovering');
859                    day.addClass('hovering');
860                } else {
861                    box.find('.day').each(function() {
862                        var time = parseInt($(this).attr('time')),
863                            start = opt.start,
864                            end = opt.end;
865
866                        if (time == hoverTime) {
867                            $(this).addClass('hovering');
868                        } else {
869                            $(this).removeClass('hovering');
870                        }
871
872                        if (
873                            (opt.start && !opt.end) &&
874                            (
875                                (opt.start < time && hoverTime >= time) ||
876                                (opt.start > time && hoverTime <= time)
877                            )
878                        ) {
879                            $(this).addClass('hovering');
880                        } else {
881                            $(this).removeClass('hovering');
882                        }
883                    });
884
885                    if (opt.start && !opt.end) {
886                        var days = countDays(hoverTime, opt.start);
887                        if (opt.hoveringTooltip) {
888                            if (typeof opt.hoveringTooltip == 'function') {
889                                tooltip = opt.hoveringTooltip(days, opt.start, hoverTime);
890                            } else if (opt.hoveringTooltip === true && days > 1) {
891                                tooltip = days + ' ' + translate('days');
892                            }
893                        }
894                    }
895                }
896            }
897
898            if (tooltip) {
899                var posDay = day.offset();
900                var posBox = box.offset();
901
902                var _left = posDay.left - posBox.left;
903                var _top = posDay.top - posBox.top;
904                _left += day.width() / 2;
905
906
907                var $tip = box.find('.date-range-length-tip');
908                var w = $tip.css({
909                    'visibility': 'hidden',
910                    'display': 'none'
911                }).html(tooltip).width();
912                var h = $tip.height();
913                _left -= w / 2;
914                _top -= h;
915                setTimeout(function() {
916                    $tip.css({
917                        left: _left,
918                        top: _top,
919                        display: 'block',
920                        'visibility': 'visible'
921                    });
922                }, 10);
923            } else {
924                box.find('.date-range-length-tip').hide();
925            }
926        }
927
928        function clearHovering() {
929            box.find('.day.hovering').removeClass('hovering');
930            box.find('.date-range-length-tip').hide();
931        }
932
933        function dateChanged(date) {
934            var value = date.val();
935            var name = date.attr('name');
936            var type = date.parents('table').hasClass('month1') ? 'month1' : 'month2';
937            var oppositeType = type === 'month1' ? 'month2' : 'month1';
938            var startDate = opt.startDate ? moment(opt.startDate) : false;
939            var endDate = opt.endDate ? moment(opt.endDate) : false;
940            var newDate = moment(opt[type])[name](value);
941
942
943            if (startDate && newDate.isSameOrBefore(startDate)) {
944                newDate = startDate.add(type === 'month2' ? 1 : 0, 'month');
945            }
946
947            if (endDate && newDate.isSameOrAfter(endDate)) {
948                newDate = endDate.add(!opt.singleMonth && type === 'month1' ? -1 : 0, 'month');
949            }
950
951            showMonth(newDate, type);
952
953            if (type === 'month1') {
954                if (opt.stickyMonths || moment(newDate).isSameOrAfter(opt[oppositeType], 'month')) {
955                    showMonth(moment(newDate).add(1, 'month'), oppositeType);
956                }
957            } else {
958                if (opt.stickyMonths || moment(newDate).isSameOrBefore(opt[oppositeType], 'month')) {
959                    showMonth(moment(newDate).add(-1, 'month'), oppositeType);
960                }
961            }
962
963            showGap();
964        }
965
966        function autoclose() {
967            if (opt.singleDate === true) {
968                if (initiated && opt.start) {
969                    if (opt.autoClose) closeDatePicker();
970                }
971            } else {
972                if (initiated && opt.start && opt.end) {
973                    if (opt.autoClose) closeDatePicker();
974                }
975            }
976        }
977
978        function checkSelectionValid() {
979            var days = Math.ceil((opt.end - opt.start) / 86400000) + 1;
980            if (opt.singleDate) { // Validate if only start is there
981                if (opt.start && !opt.end)
982                    box.find('.drp_top-bar').removeClass('error').addClass('normal');
983                else
984                    box.find('.drp_top-bar').removeClass('error').removeClass('normal');
985            } else if (opt.maxDays && days > opt.maxDays) {
986                opt.start = false;
987                opt.end = false;
988                box.find('.day').removeClass('checked');
989                box.find('.drp_top-bar').removeClass('normal').addClass('error').find('.error-top').html(translate('less-than').replace('%d', opt.maxDays));
990            } else if (opt.minDays && days < opt.minDays) {
991                opt.start = false;
992                opt.end = false;
993                box.find('.day').removeClass('checked');
994                box.find('.drp_top-bar').removeClass('normal').addClass('error').find('.error-top').html(translate('more-than').replace('%d', opt.minDays));
995            } else {
996                if (opt.start || opt.end)
997                    box.find('.drp_top-bar').removeClass('error').addClass('normal');
998                else
999                    box.find('.drp_top-bar').removeClass('error').removeClass('normal');
1000            }
1001
1002            if ((opt.singleDate && opt.start && !opt.end) || (!opt.singleDate && opt.start && opt.end)) {
1003                box.find('.apply-btn').removeClass('disabled');
1004            } else {
1005                box.find('.apply-btn').addClass('disabled');
1006            }
1007
1008            if (opt.batchMode) {
1009                if (
1010                    (opt.start && opt.startDate && compare_day(opt.start, opt.startDate) < 0) ||
1011                    (opt.end && opt.endDate && compare_day(opt.end, opt.endDate) > 0)
1012                ) {
1013                    opt.start = false;
1014                    opt.end = false;
1015                    box.find('.day').removeClass('checked');
1016                }
1017            }
1018        }
1019
1020        function showSelectedInfo(forceValid, silent) {
1021            box.find('.start-day').html('...');
1022            box.find('.end-day').html('...');
1023            box.find('.selected-days').hide();
1024            if (opt.start) {
1025                box.find('.start-day').html(getDateString(new Date(parseInt(opt.start))));
1026            }
1027            if (opt.end) {
1028                box.find('.end-day').html(getDateString(new Date(parseInt(opt.end))));
1029            }
1030            var dateRange;
1031            if (opt.start && opt.singleDate) {
1032                box.find('.apply-btn').removeClass('disabled');
1033                dateRange = getDateString(new Date(opt.start));
1034                opt.setValue.call(selfDom, dateRange, getDateString(new Date(opt.start)), getDateString(new Date(opt.end)));
1035
1036                if (initiated && !silent) {
1037                    $(self).trigger('datepicker-change', {
1038                        'value': dateRange,
1039                        'date1': new Date(opt.start)
1040                    });
1041                }
1042            } else if (opt.start && opt.end) {
1043                box.find('.selected-days').show().find('.selected-days-num').html(countDays(opt.end, opt.start));
1044                box.find('.apply-btn').removeClass('disabled');
1045                dateRange = getDateString(new Date(opt.start)) + opt.separator + getDateString(new Date(opt.end));
1046                opt.setValue.call(selfDom, dateRange, getDateString(new Date(opt.start)), getDateString(new Date(opt.end)));
1047                if (initiated && !silent) {
1048                    $(self).trigger('datepicker-change', {
1049                        'value': dateRange,
1050                        'date1': new Date(opt.start),
1051                        'date2': new Date(opt.end)
1052                    });
1053                }
1054            } else if (forceValid) {
1055                box.find('.apply-btn').removeClass('disabled');
1056            } else {
1057                box.find('.apply-btn').addClass('disabled');
1058            }
1059        }
1060
1061        function countDays(start, end) {
1062            return Math.abs(moment(start).diff(moment(end), 'd')) + 1;
1063        }
1064
1065        function setDateRange(date1, date2, silent) {
1066            if (date1.getTime() > date2.getTime()) {
1067                var tmp = date2;
1068                date2 = date1;
1069                date1 = tmp;
1070                tmp = null;
1071            }
1072            var valid = true;
1073            if (opt.startDate && compare_day(date1, opt.startDate) < 0) valid = false;
1074            if (opt.endDate && compare_day(date2, opt.endDate) > 0) valid = false;
1075            if (!valid) {
1076                showMonth(opt.startDate, 'month1');
1077                showMonth(nextMonth(opt.startDate), 'month2');
1078                showGap();
1079                return;
1080            }
1081
1082            opt.start = date1.getTime();
1083            opt.end = date2.getTime();
1084
1085            if (opt.time.enabled) {
1086                renderTime('time1', date1);
1087                renderTime('time2', date2);
1088            }
1089
1090            if (opt.stickyMonths || (compare_day(date1, date2) > 0 && compare_month(date1, date2) === 0)) {
1091                if (opt.lookBehind) {
1092                    date1 = prevMonth(date2);
1093                } else {
1094                    date2 = nextMonth(date1);
1095                }
1096            }
1097
1098            if (opt.stickyMonths && opt.endDate !== false && compare_month(date2, opt.endDate) > 0) {
1099                date1 = prevMonth(date1);
1100                date2 = prevMonth(date2);
1101            }
1102
1103            if (!opt.stickyMonths) {
1104                if (compare_month(date1, date2) === 0) {
1105                    if (opt.lookBehind) {
1106                        date1 = prevMonth(date2);
1107                    } else {
1108                        date2 = nextMonth(date1);
1109                    }
1110                }
1111            }
1112
1113            showMonth(date1, 'month1');
1114            showMonth(date2, 'month2');
1115            showGap();
1116            checkSelectionValid();
1117            showSelectedInfo(false, silent);
1118            autoclose();
1119        }
1120
1121        function setSingleDate(date1) {
1122
1123            var valid = true;
1124            if (opt.startDate && compare_day(date1, opt.startDate) < 0) valid = false;
1125            if (opt.endDate && compare_day(date1, opt.endDate) > 0) valid = false;
1126            if (!valid) {
1127                showMonth(opt.startDate, 'month1');
1128                return;
1129            }
1130
1131            opt.start = date1.getTime();
1132
1133
1134            if (opt.time.enabled) {
1135                renderTime('time1', date1);
1136
1137            }
1138            showMonth(date1, 'month1');
1139            if (opt.singleMonth !== true) {
1140                var date2 = nextMonth(date1);
1141                showMonth(date2, 'month2');
1142            }
1143            showGap();
1144            showSelectedInfo();
1145            autoclose();
1146        }
1147
1148        function showSelectedDays() {
1149            if (!opt.start && !opt.end) return;
1150            box.find('.day').each(function() {
1151                var time = parseInt($(this).attr('time')),
1152                    start = opt.start,
1153                    end = opt.end;
1154                if (opt.time.enabled) {
1155                    time = moment(time).startOf('day').valueOf();
1156                    start = moment(start || moment().valueOf()).startOf('day').valueOf();
1157                    end = moment(end || moment().valueOf()).startOf('day').valueOf();
1158                }
1159                if (
1160                    (opt.start && opt.end && end >= time && start <= time) ||
1161                    (opt.start && !opt.end && moment(start).format('YYYY-MM-DD') == moment(time).format('YYYY-MM-DD'))
1162                ) {
1163                    $(this).addClass('checked');
1164                } else {
1165                    $(this).removeClass('checked');
1166                }
1167
1168                //add first-date-selected class name to the first date selected
1169                if (opt.start && moment(start).format('YYYY-MM-DD') == moment(time).format('YYYY-MM-DD')) {
1170                    $(this).addClass('first-date-selected');
1171                } else {
1172                    $(this).removeClass('first-date-selected');
1173                }
1174                //add last-date-selected
1175                if (opt.end && moment(end).format('YYYY-MM-DD') == moment(time).format('YYYY-MM-DD')) {
1176                    $(this).addClass('last-date-selected');
1177                } else {
1178                    $(this).removeClass('last-date-selected');
1179                }
1180            });
1181
1182            box.find('.week-number').each(function() {
1183                if ($(this).attr('data-start-time') == opt.startWeek) {
1184                    $(this).addClass('week-number-selected');
1185                }
1186            });
1187        }
1188
1189        function showMonth(date, month) {
1190            date = moment(date).toDate();
1191            var monthElement = generateMonthElement(date, month);
1192            var yearElement = generateYearElement(date, month);
1193
1194            box.find('.' + month + ' .month-name').html(monthElement + ' ' + yearElement);
1195            box.find('.' + month + ' tbody').html(createMonthHTML(date));
1196            opt[month] = date;
1197            updateSelectableRange();
1198            bindEvents();
1199        }
1200
1201        function generateMonthElement(date, month) {
1202            var range;
1203            var startDate = opt.startDate ? moment(opt.startDate).add(!opt.singleMonth && month === 'month2' ? 1 : 0, 'month') : false;
1204            var endDate = opt.endDate ? moment(opt.endDate).add(!opt.singleMonth && month === 'month1' ? -1 : 0, 'month') : false;
1205            date = moment(date);
1206
1207            if (!opt.monthSelect ||
1208                startDate && endDate && startDate.isSame(endDate, 'month')) {
1209                return '<div class="month-element">' + nameMonth(date.get('month')) + '</div>';
1210            }
1211
1212            range = [
1213                startDate && date.isSame(startDate, 'year') ? startDate.get('month') : 0,
1214                date ? date.get('month') : 11
1215            ];
1216
1217            if (range[0] === range[1]) {
1218                return '<div class="month-element">' + nameMonth(date.get('month')) + '</div>';
1219            }
1220
1221            return generateSelect(
1222                'month',
1223                generateSelectData(
1224                    range,
1225                    date.get('month'),
1226                    function(value) { return nameMonth(value); }
1227                )
1228            );
1229        }
1230
1231        function generateYearElement(date, month) {
1232            date = moment(date);
1233            var startDate = opt.startDate ? moment(opt.startDate).add(!opt.singleMonth && month 
1233=== 'month2' ? 1 : 0, 'month') : false;
1234            var endDate = opt.endDate ? moment(opt.endDate).add(!opt.singleMonth && month === 'month1' ? -1 : 0, 'month') : false;
1235            var fullYear = date.get('year');
1236            var isYearFunction = opt.yearSelect && typeof opt.yearSelect === 'function';
1237            var range;
1238
1239            if (!opt.yearSelect ||
1240                startDate && endDate && startDate.isSame(moment(endDate), 'year')) {
1241                return '<div class="month-element">' + fullYear + '</div>';
1242            }
1243
1244            range = isYearFunction ? opt.yearSelect(fullYear) : opt.yearSelect.slice();
1245
1246            range = [
1247                startDate ? Math.max(range[0], startDate.get('year')) : Math.min(range[0], fullYear),
1248                endDate ? Math.min(range[1], endDate.get('year')) : Math.max(range[1], fullYear)
1249            ];
1250
1251            return generateSelect('year', generateSelectData(range, fullYear));
1252        }
1253
1254
1255        function generateSelectData(range, current, valueBeautifier) {
1256            var data = [];
1257            valueBeautifier = valueBeautifier || function(value) { return value; };
1258
1259            for (var i = range[0]; i <= range[1]; i++) {
1260                data.push({
1261                    value: i,
1262                    text: valueBeautifier(i),
1263                    isCurrent: i === current
1264                });
1265            }
1266
1267            return data;
1268        }
1269
1270        function generateSelect(name, data) {
1271            var select = '<div class="select-wrapper"><select class="' + name + '" name="' + name + '">';
1272            var current;
1273
1274            for (var i = 0, l = data.length; i < l; i++) {
1275                select += '<option value="' + data[i].value + '"' + (data[i].isCurrent ? ' selected' : '') + '>';
1276                select += data[i].text;
1277                select += '</option>';
1278
1279                if (data[i].isCurrent) {
1280                    current = data[i].text;
1281                }
1282            }
1283
1284            select += '</select>' + current + '</div>';
1285
1286            return select;
1287        }
1288
1289        function bindEvents() {
1290            box.find('.day').off("click").click(function(evt) {
1291                dayClicked($(this));
1292            });
1293
1294            box.find('.day').off("mouseenter").mouseenter(function(evt) {
1295                dayHovering($(this));
1296            });
1297
1298            box.find('.day').off("mouseleave").mouseleave(function(evt) {
1299                box.find('.date-range-length-tip').hide();
1300                if (opt.singleDate) {
1301                    clearHovering();
1302                }
1303            });
1304
1305            box.find('.week-number').off("click").click(function(evt) {
1306                weekNumberClicked($(this));
1307            });
1308
1309            box.find('.month').off("change").change(function(evt) {
1310                dateChanged($(this));
1311            });
1312
1313            box.find('.year').off("change").change(function(evt) {
1314                dateChanged($(this));
1315            });
1316        }
1317
1318        function showTime(date, name) {
1319            box.find('.' + name).append(getTimeHTML());
1320            renderTime(name, date);
1321        }
1322
1323        function nameMonth(m) {
1324            return translate('month-name')[m];
1325        }
1326
1327        function getDateString(d) {
1328            return moment(d).format(opt.format);
1329        }
1330
1331        function showGap() {
1332            showSelectedDays();
1333            var m1 = parseInt(moment(opt.month1).format('YYYYMM'));
1334            var m2 = parseInt(moment(opt.month2).format('YYYYMM'));
1335            var p = Math.abs(m1 - m2);
1336            var shouldShow = (p > 1 && p != 89);
1337            if (shouldShow) {
1338                box.addClass('has-gap').removeClass('no-gap').find('.gap').css('visibility', 'visible');
1339            } else {
1340                box.removeClass('has-gap').addClass('no-gap').find('.gap').css('visibility', 'hidden');
1341            }
1342            var h1 = box.find('table.month1').height();
1343            var h2 = box.find('table.month2').height();
1344            box.find('.gap').height(Math.max(h1, h2) + 10);
1345        }
1346
1347        function closeDatePicker() {
1348            if (opt.alwaysOpen) return;
1349
1350            var afterAnim = function() {
1351                $(self).data('date-picker-opened', false);
1352                $(self).trigger('datepicker-closed', {
1353                    relatedTarget: box
1354                });
1355            };
1356            if (opt.customCloseAnimation) {
1357                opt.customCloseAnimation.call(box.get(0), afterAnim);
1358            } else {
1359                $(box).slideUp(opt.duration, afterAnim);
1360            }
1361            $(self).trigger('datepicker-close', {
1362                relatedTarget: box
1363            });
1364        }
1365
1366        function redrawDatePicker() {
1367            showMonth(opt.month1, 'month1');
1368            showMonth(opt.month2, 'month2');
1369        }
1370
1371        function compare_month(m1, m2) {
1372            var p = parseInt(moment(m1).format('YYYYMM')) - parseInt(moment(m2).format('YYYYMM'));
1373            if (p > 0) return 1;
1374            if (p === 0) return 0;
1375            return -1;
1376        }
1377
1378        function compare_day(m1, m2) {
1379            var p = parseInt(moment(m1).format('YYYYMMDD')) - parseInt(moment(m2).format('YYYYMMDD'));
1380            if (p > 0) return 1;
1381            if (p === 0) return 0;
1382            return -1;
1383        }
1384
1385        function nextMonth(month) {
1386            return moment(month).add(1, 'months').toDate();
1387        }
1388
1389        function prevMonth(month) {
1390            return moment(month).add(-1, 'months').toDate();
1391        }
1392
1393        function getTimeHTML() {
1394            return '<div>' +
1395                '<span>' + translate('Time') + ': <span class="hour-val">00</span>:<span class="minute-val">00</span></span>' +
1396                '</div>' +
1397                '<div class="hour">' +
1398                '<label>' + translate('Hour') + ': <input type="range" class="hour-range" name="hour" min="0" max="23"></label>' +
1399                '</div>' +
1400                '<div class="minute">' +
1401                '<label>' + translate('Minute') + ': <input type="range" class="minute-range" name="minute" min="0" max="59"></label>' +
1402                '</div>';
1403        }
1404
1405        function createDom() {
1406            var html = '<div class="date-picker-wrapper';
1407            if (opt.extraClass) html += ' ' + opt.extraClass + ' ';
1408            if (opt.singleDate) html += ' single-date ';
1409            if (!opt.showShortcuts) html += ' no-shortcuts ';
1410            if (!opt.showTopbar) html += ' no-topbar ';
1411            if (opt.customTopBar) html += ' custom-topbar ';
1412            html += '">';
1413
1414            if (opt.showTopbar) {
1415                html += '<div class="drp_top-bar">';
1416
1417                if (opt.customTopBar) {
1418                    if (typeof opt.customTopBar == 'function') opt.customTopBar = opt.customTopBar();
1419                    html += '<div class="custom-top">' + opt.customTopBar + '</div>';
1420                } else {
1421                    html += '<div class="normal-top">' +
1422                        '<span class="selection-top">' + translate('selected') + ' </span> <b class="start-day">...</b>';
1423                    if (!opt.singleDate) {
1424                        html += ' <span class="separator-day">' + opt.separator + '</span> <b class="end-day">...</b> <i class="selected-days">(<span class="selected-days-num">3</span> ' + translate('days') + ')</i>';
1425                    }
1426                    html += '</div>';
1427                    html += '<div class="error-top">error</div>' +
1428                        '<div class="default-top">default</div>';
1429                }
1430
1431                html += '<input type="button" class="apply-btn disabled' + getApplyBtnClass() + '" value="' + translate('apply') + '" />';
1432                html += '</div>';
1433            }
1434
1435            var _colspan = opt.showWeekNumbers ? 6 : 5;
1436
1437            var arrowPrev = '&lt;';
1438            if (opt.customArrowPrevSymbol) arrowPrev = opt.customArrowPrevSymbol;
1439
1440            var arrowNext = '&gt;';
1441            if (opt.customArrowNextSymbol) arrowNext = opt.customArrowNextSymbol;
1442
1443            html += '<div class="month-wrapper">' +
1444                '   <table class="month1" cellspacing="0" border="0" cellpadding="0">' +
1445                '       <thead>' +
1446                '           <tr class="caption">' +
1447                '               <th>' +
1448                '                   <span class="prev">' +
1449                arrowPrev +
1450                '                   </span>' +
1451                '               </th>' +
1452                '               <th colspan="' + _colspan + '" class="month-name">' +
1453                '               </th>' +
1454                '               <th>' +
1455                (opt.singleDate || !opt.stickyMonths ? '<span class="next">' + arrowNext + '</span>' : '') +
1456                '               </th>' +
1457                '           </tr>' +
1458                '           <tr class="week-name">' + getWeekHead() +
1459                '       </thead>' +
1460                '       <tbody></tbody>' +
1461                '   </table>';
1462
1463            if (hasMonth2()) {
1464                html += '<div class="gap">' + getGapHTML() + '</div>' +
1465                    '<table class="month2" cellspacing="0" border="0" cellpadding="0">' +
1466                    '   <thead>' +
1467                    '   <tr class="caption">' +
1468                    '       <th>' +
1469                    (!opt.stickyMonths ? '<span class="prev">' + arrowPrev + '</span>' : '') +
1470                    '       </th>' +
1471                    '       <th colspan="' + _colspan + '" class="month-name">' +
1472                    '       </th>' +
1473                    '       <th>' +
1474                    '           <span class="next">' + arrowNext + '</span>' +
1475                    '       </th>' +
1476                    '   </tr>' +
1477                    '   <tr class="week-name">' + getWeekHead() +
1478                    '   </thead>' +
1479                    '   <tbody></tbody>' +
1480                    '</table>';
1481
1482            }
1483            //+'</div>'
1484            html += '<div class="dp-clearfix"></div>' +
1485                '<div class="time">' +
1486                '<div class="time1"></div>';
1487            if (!opt.singleDate) {
1488                html += '<div class="time2"></div>';
1489            }
1490            html += '</div>' +
1491                '<div class="dp-clearfix"></div>' +
1492                '</div>';
1493
1494            html += '<div class="footer">';
1495            if (opt.showShortcuts) {
1496                html += '<div class="shortcuts"><b>' + translate('shortcuts') + '</b>';
1497
1498                var data = opt.shortcuts;
1499                if (data) {
1500                    var name;
1501                    if (data['prev-days'] && data['prev-days'].length > 0) {
1502                        html += '&nbsp;<span class="prev-days">' + translate('past');
1503                        for (var i = 0; i < data['prev-days'].length; i++) {
1504                            name = data['prev-days'][i];
1505                            name += (data['prev-days'][i] > 1) ? translate('days') : translate('day');
1506                            html += ' <a href="javascript:;" shortcut="day,-' + data['prev-days'][i] + '">' + name + '</a>';
1507                        }
1508                        html += '</span>';
1509                    }
1510
1511                    if (data['next-days'] && data['next-days'].length > 0) {
1512                        html += '&nbsp;<span class="next-days">' + translate('following');
1513                        for (var i = 0; i < data['next-days'].length; i++) {
1514                            name = data['next-days'][i];
1515                            name += (data['next-days'][i] > 1) ? translate('days') : translate('day');
1516                            html += ' <a href="javascript:;" shortcut="day,' + data['next-days'][i] + '">' + name + '</a>';
1517                        }
1518                        html += '</span>';
1519                    }
1520
1521                    if (data.prev && data.prev.length > 0) {
1522                        html += '&nbsp;<span class="prev-buttons">' + translate('previous');
1523                        for (var i = 0; i < data.prev.length; i++) {
1524                            name = translate('prev-' + data.prev[i]);
1525                            html += ' <a href="javascript:;" shortcut="prev,' + data.prev[i] + '">' + name + '</a>';
1526                        }
1527                        html += '</span>';
1528                    }
1529
1530                    if (data.next && data.next.length > 0) {
1531                        html += '&nbsp;<span class="next-buttons">' + translate('next');
1532                        for (var i = 0; i < data.next.length; i++) {
1533                            name = translate('next-' + data.next[i]);
1534                            html += ' <a href="javascript:;" shortcut="next,' + data.next[i] + '">' + name + '</a>';
1535                        }
1536                        html += '</span>';
1537                    }
1538                }
1539
1540                if (opt.customShortcuts) {
1541                    for (var i = 0; i < opt.customShortcuts.length; i++) {
1542                        var sh = opt.customShortcuts[i];
1543                        html += '&nbsp;<span class="custom-shortcut"><a href="javascript:;" shortcut="custom">' + sh.name + '</a></span>';
1544                    }
1545                }
1546                html += '</div>';
1547            }
1548
1549            // Add Custom Values Dom
1550            if (opt.showCustomValues) {
1551                html += '<div class="customValues"><b>' + (opt.customValueLabel || translate('custom-values')) + '</b>';
1552
1553                if (opt.customValues) {
1554                    for (var i = 0; i < opt.customValues.length; i++) {
1555                        var val = opt.customValues[i];
1556                        html += '&nbsp;<span class="custom-value"><a href="javascript:;" custom="' + val.value + '">' + val.name + '</a></span>';
1557                    }
1558                }
1559            }
1560
1561            html += '</div></div>';
1562
1563
1564            return $(html);
1565        }
1566
1567        function getApplyBtnClass() {
1568            var klass = '';
1569            if (opt.autoClose === true) {
1570                klass += ' hide';
1571            }
1572            if (opt.applyBtnClass !== '') {
1573                klass += ' ' + opt.applyBtnClass;
1574            }
1575            return klass;
1576        }
1577
1578        function getWeekHead() {
1579            var prepend = opt.showWeekNumbers ? '<th>' + translate('week-number') + '</th>' : '';
1580            if (opt.startOfWeek == 'monday') {
1581                return prepend + '<th>' + translate('week-1') + '</th>' +
1582                    '<th>' + translate('week-2') + '</th>' +
1583                    '<th>' + translate('week-3') + '</th>' +
1584                    '<th>' + translate('week-4') + '</th>' +
1585                    '<th>' + translate('week-5') + '</th>' +
1586                    '<th>' + translate('week-6') + '</th>' +
1587                    '<th>' + translate('week-7') + '</th>';
1588            } else {
1589                return prepend + '<th>' + translate('week-7') + '</th>' +
1590                    '<th>' + translate('week-1') + '</th>' +
1591                    '<th>' + translate('week-2') + '</th>' +
1592                    '<th>' + translate('week-3') + '</th>' +
1593                    '<th>' + translate('week-4') + '</th>' +
1594                    '<th>' + translate('week-5') + '</th>' +
1595                    '<th>' + translate('week-6') + '</th>';
1596            }
1597        }
1598
1599        function isMonthOutOfBounds(month) {
1600            month = moment(month);
1601            if (opt.startDate && month.endOf('month').isBefore(opt.startDate)) {
1602                return true;
1603            }
1604            if (opt.endDate && month.startOf('month').isAfter(opt.endDate)) {
1605                return true;
1606            }
1607            return false;
1608        }
1609
1610        function getGapHTML() {
1611            var html = ['<div class="gap-top-mask"></div><div class="gap-bottom-mask"></div><div class="gap-lines">'];
1612            for (var i = 0; i < 20; i++) {
1613                html.push('<div class="gap-line">' +
1614                    '<div class="gap-1"></div>' +
1615                    '<div class="gap-2"></div>' +
1616                    '<div class="gap-3"></div>' +
1617                    '</div>');
1618            }
1619            html.push('</div>');
1620            return html.join('');
1621        }
1622
1623        function hasMonth2() {
1624            return (!opt.singleMonth);
1625        }
1626
1627        function attributesCallbacks(initialObject, callbacksArray, today) {
1628            var resultObject = $.extend(true, {}, initialObject);
1629
1630            $.each(callbacksArray, function(cbAttrIndex, cbAttr) {
1631                var addAttributes = cbAttr(today);
1632                for (var attr in addAttributes) {
1633                    if (resultObject.hasOwnProperty(attr)) {
1634                        resultObject[attr] += addAttributes[attr];
1635                    } else {
1636                        resultObject[attr] = addAttributes[attr];
1637                    }
1638                }
1639            });
1640
1641            var attrString = '';
1642
1643            for (var attr in resultObject) {
1644                if (resultObject.hasOwnProperty(attr)) {
1645                    attrString += attr + '="' + resultObject[attr] + '" ';
1646                }
1647            }
1648
1649            return attrString;
1650        }
1651
1652        function createMonthHTML(d) {
1653            var days = [];
1654            d.setDate(1);
1655            var lastMonth = new Date(d.getTime() - 86400000);
1656            var now = new Date();
1657
1658            var dayOfWeek = d.getDay();
1659            if ((dayOfWeek === 0) && (opt.startOfWeek === 'monday')) {
1660                // add one week
1661                dayOfWeek = 7;
1662            }
1663            var today, valid;
1664
1665            if (dayOfWeek > 0) {
1666                for (var i = dayOfWeek; i > 0; i--) {
1667                    var day = new Date(d.getTime() - 86400000 * i);
1668                    valid = isValidTime(day.getTime());
1669                    if (opt.startDate && compare_day(day, opt.startDate) < 0) valid = false;
1670                    if (opt.endDate && compare_day(day, opt.endDate) > 0) valid = false;
1671                    days.push({
1672                        date: day,
1673                        type: 'lastMonth',
1674                        day: day.getDate(),
1675                        time: day.getTime(),
1676                        valid: valid
1677                    });
1678                }
1679            }
1680            var toMonth = d.getMonth();
1681            for (var i = 0; i < 40; i++) {
1682                today = moment(d).add(i, 'days').toDate();
1683                valid = isValidTime(today.getTime());
1684                if (opt.startDate && compare_day(today, opt.startDate) < 0) valid = false;
1685                if (opt.endDate && compare_day(today, opt.endDate) > 0) valid = false;
1686                days.push({
1687                    date: today,
1688                    type: today.getMonth() == toMonth ? 'toMonth' : 'nextMonth',
1689                    day: today.getDate(),
1690                    time: today.getTime(),
1691                    valid: valid
1692                });
1693            }
1694            var html = [];
1695            for (var week = 0; week < 6; week++) {
1696                if (days[week * 7].type == 'nextMonth') break;
1697                html.push('<tr>');
1698
1699                for (var day = 0; day < 7; day++) {
1700                    var _day = (opt.startOfWeek == 'monday') ? day + 1 : day;
1701                    today = days[week * 7 + _day];
1702                    var highlightToday = moment(today.time).format('L') == moment(now).format('L');
1703                    today.extraClass = '';
1704                    today.tooltip = '';
1705                    if (today.valid && opt.beforeShowDay && typeof opt.beforeShowDay == 'function') {
1706                        var _r = opt.beforeShowDay(moment(today.time).toDate());
1707                        today.valid = _r[0];
1708                        today.extraClass = _r[1] || '';
1709                        today.tooltip = _r[2] || '';
1710                        if (today.tooltip !== '') today.extraClass += ' has-tooltip ';
1711                    }
1712
1713                    var todayDivAttr = {
1714                        time: today.time,
1715                        'data-tooltip': today.tooltip,
1716                        'class': 'day ' + today.type + ' ' + today.extraClass + ' ' + (today.valid ? 'valid' : 'invali
1716d') + ' ' + (highlightToday ? 'real-today' : '')
1717                    };
1718
1719                    if (day === 0 && opt.showWeekNumbers) {
1720                        html.push('<td><div class="week-number" data-start-time="' + today.time + '">' + opt.getWeekNumber(today.date) + '</div></td>');
1721                    }
1722
1723                    html.push('<td ' + attributesCallbacks({}, opt.dayTdAttrs, today) + '><div ' + attributesCallbacks(todayDivAttr, opt.dayDivAttrs, today) + '>' + showDayHTML(today.time, today.day) + '</div></td>');
1724                }
1725                html.push('</tr>');
1726            }
1727            return html.join('');
1728        }
1729
1730        function showDayHTML(time, date) {
1731            if (opt.showDateFilter && typeof opt.showDateFilter == 'function') return opt.showDateFilter(time, date);
1732            return date;
1733        }
1734
1735        function getLanguages() {
1736            if (opt.language == 'auto') {
1737                var language = navigator.language ? navigator.language : navigator.browserLanguage;
1738                if (!language) {
1739                    return $.dateRangePickerLanguages['default'];
1740                }
1741                language = language.toLowerCase();
1742                if(language in $.dateRangePickerLanguages){
1743                    return $.dateRangePickerLanguages[language];
1744                }
1745
1746                return $.dateRangePickerLanguages['default'];
1747            } else if (opt.language && opt.language in $.dateRangePickerLanguages) {
1748                return $.dateRangePickerLanguages[opt.language];
1749            } else {
1750                return $.dateRangePickerLanguages['default'];
1751            }
1752        }
1753
1754        /**
1755         * Translate language string, try both the provided translation key, as the lower case version
1756         */
1757        function translate(translationKey) {
1758            var translationKeyLowerCase = translationKey.toLowerCase();
1759            var result = (translationKey in languages) ? languages[translationKey] : (translationKeyLowerCase in languages) ? languages[translationKeyLowerCase] : null;
1760            var defaultLanguage = $.dateRangePickerLanguages['default'];
1761            if (result == null) result = (translationKey in defaultLanguage) ? defaultLanguage[translationKey] : (translationKeyLowerCase in defaultLanguage) ? defaultLanguage[translationKeyLowerCase] : '';
1762
1763            return result;
1764        }
1765
1766        function getDefaultTime() {
1767            var defaultTime = opt.defaultTime ? opt.defaultTime : new Date();
1768
1769            if (opt.lookBehind) {
1770                if (opt.startDate && compare_month(defaultTime, opt.startDate) < 0) defaultTime = nextMonth(moment(opt.startDate).toDate());
1771                if (opt.endDate && compare_month(defaultTime, opt.endDate) > 0) defaultTime = moment(opt.endDate).toDate();
1772            } else {
1773                if (opt.startDate && compare_month(defaultTime, opt.startDate) < 0) defaultTime = moment(opt.startDate).toDate();
1774                if (opt.endDate && compare_month(nextMonth(defaultTime), opt.endDate) > 0) defaultTime = prevMonth(moment(opt.endDate).toDate());
1775            }
1776
1777            if (opt.singleDate) {
1778                if (opt.startDate && compare_month(defaultTime, opt.startDate) < 0) defaultTime = moment(opt.startDate).toDate();
1779                if (opt.endDate && compare_month(defaultTime, opt.endDate) > 0) defaultTime = moment(opt.endDate).toDate();
1780            }
1781
1782            return defaultTime;
1783        }
1784
1785        function resetMonthsView(time) {
1786            if (!time) {
1787                time = getDefaultTime();
1788            }
1789
1790            if (opt.lookBehind) {
1791                showMonth(prevMonth(time), 'month1');
1792                showMonth(time, 'month2');
1793            } else {
1794                showMonth(time, 'month1');
1795                showMonth(nextMonth(time), 'month2');
1796            }
1797
1798            if (opt.singleDate) {
1799                showMonth(time, 'month1');
1800            }
1801
1802            showSelectedDays();
1803            showGap();
1804        }
1805
1806        function outsideClickClose(evt) {
1807            if (!IsOwnDatePickerClicked(evt, self[0])) {
1808                if (box.is(':visible')) closeDatePicker();
1809            }
1810        }
1811
1812    };
1813}));

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.