PageSourceSearch

https://uecc-hexatrust.com/assets/js/bootstrap-datetimepicker.js

js uecc-hexatrust.com collected 2026-10-04 14:53:55 UTC 105,163 bytes, 2,596 lines download raw bytes

1/*! version : 4.17.37
2 =========================================================
3 bootstrap-datetimejs
4 https://github.com/Eonasdan/bootstrap-datetimepicker
5 Copyright (c) 2015 Jonathan Peterson
6 =========================================================
7 */
8/*
9 The MIT License (MIT)
10
11 Copyright (c) 2015 Jonathan Peterson
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in
21 all copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 THE SOFTWARE.
30 */
31/*global define:false */
32/*global exports:false */
33/*global require:false */
34/*global jQuery:false */
35/*global moment:false */
36
37/*
38
39
40     Creative Tim Modifications
41
42     Line: 298 - we added class btn-primary for custom styling button.
43
44
45*/
46(function (factory) {
47    'use strict';
48    if (typeof define === 'function' && define.amd) {
49        // AMD is used - Register as an anonymous module.
50        define(['jquery', 'moment'], factory);
51    } else if (typeof exports === 'object') {
52        factory(require('jquery'), require('moment'));
53    } else {
54        // Neither AMD nor CommonJS used. Use global variables.
55        if (typeof jQuery === 'undefined') {
56            throw 'bootstrap-datetimepicker requires jQuery to be loaded first';
57        }
58        if (typeof moment === 'undefined') {
59            throw 'bootstrap-datetimepicker requires Moment.js to be loaded first';
60        }
61        factory(jQuery, moment);
62    }
63}(function ($, moment) {
64    'use strict';
65    if (!moment) {
66        throw new Error('bootstrap-datetimepicker requires Moment.js to be loaded first');
67    }
68
69    var dateTimePicker = function (element, options) {
70        var picker = {},
71            date,
72            viewDate,
73            unset = true,
74            input,
75            component = false,
76            widget = false,
77            use24Hours,
78            minViewModeNumber = 0,
79            actualFormat,
80            parseFormats,
81            currentViewMode,
82            datePickerModes = [
83                {
84                    clsName: 'days',
85                    navFnc: 'M',
86                    navStep: 1
87                },
88                {
89                    clsName: 'months',
90                    navFnc: 'y',
91                    navStep: 1
92                },
93                {
94                    clsName: 'years',
95                    navFnc: 'y',
96                    navStep: 10
97                },
98                {
99                    clsName: 'decades',
100                    navFnc: 'y',
101                    navStep: 100
102                }
103            ],
104            viewModes = ['days', 'months', 'years', 'decades'],
105            verticalModes = ['top', 'bottom', 'auto'],
106            horizontalModes = ['left', 'right', 'auto'],
107            toolbarPlacements = ['default', 'top', 'bottom'],
108            keyMap = {
109                'up': 38,
110                38: 'up',
111                'down': 40,
112                40: 'down',
113                'left': 37,
114                37: 'left',
115                'right': 39,
116                39: 'right',
117                'tab': 9,
118                9: 'tab',
119                'escape': 27,
120                27: 'escape',
121                'enter': 13,
122                13: 'enter',
123                'pageUp': 33,
124                33: 'pageUp',
125                'pageDown': 34,
126                34: 'pageDown',
127                'shift': 16,
128                16: 'shift',
129                'control': 17,
130                17: 'control',
131                'space': 32,
132                32: 'space',
133                't': 84,
134                84: 't',
135                'delete': 46,
136                46: 'delete'
137            },
138            keyState = {},
139
140            /********************************************************************************
141             *
142             * Private functions
143             *
144             ********************************************************************************/
145            getMoment = function (d) {
146                var tzEnabled = false,
147                    returnMoment,
148                    currentZoneOffset,
149                    incomingZoneOffset,
150                    timeZoneIndicator,
151                    dateWithTimeZoneInfo;
152
153                if (moment.tz !== undefined && options.timeZone !== undefined && options.timeZone !== null && options.timeZone !== '') {
154                    tzEnabled = true;
155                }
156                if (d === undefined || d === null) {
157                    if (tzEnabled) {
158                        returnMoment = moment().tz(options.timeZone).startOf('d');
159                    } else {
160                        returnMoment = moment().startOf('d');
161                    }
162                } else {
163                    if (tzEnabled) {
164                        currentZoneOffset = moment().tz(options.timeZone).utcOffset();
165                        incomingZoneOffset = moment(d, parseFormats, options.useStrict).utcOffset();
166                        if (incomingZoneOffset !== currentZoneOffset) {
167                            timeZoneIndicator = moment().tz(options.timeZone).format('Z');
168                            dateWithTimeZoneInfo = moment(d, parseFormats, options.useStrict).format('YYYY-MM-DD[T]HH:mm:ss') + timeZoneIndicator;
169                            returnMoment = moment(dateWithTimeZoneInfo, parseFormats, options.useStrict).tz(options.timeZone);
170                        } else {
171                            returnMoment = moment(d, parseFormats, options.useStrict).tz(options.timeZone);
172                        }
173                    } else {
174                        returnMoment = moment(d, parseFormats, options.useStrict);
175                    }
176                }
177                return returnMoment;
178            },
179            isEnabled = function (granularity) {
180                if (typeof granularity !== 'string' || granularity.length > 1) {
181                    throw new TypeError('isEnabled expects a single character string parameter');
182                }
183                switch (granularity) {
184                    case 'y':
185                        return actualFormat.indexOf('Y') !== -1;
186                    case 'M':
187                        return actualFormat.indexOf('M') !== -1;
188                    case 'd':
189                        return actualFormat.toLowerCase().indexOf('d') !== -1;
190                    case 'h':
191                    case 'H':
192                        return actualFormat.toLowerCase().indexOf('h') !== -1;
193                    case 'm':
194                        return actualFormat.indexOf('m') !== -1;
195                    case 's':
196                        return actualFormat.indexOf('s') !== -1;
197                    default:
198                        return false;
199                }
200            },
201            hasTime = function () {
202                return (isEnabled('h') || isEnabled('m') || isEnabled('s'));
203            },
204
205            hasDate = function () {
206                return (isEnabled('y') || isEnabled('M') || isEnabled('d'));
207            },
208
209            getDatePickerTemplate = function () {
210                var headTemplate = $('<thead>')
211                        .append($('<tr>')
212                            .append($('<th>').addClass('prev').attr('data-action', 'previous')
213                                .append($('<span>').addClass(options.icons.previous))
214                                )
215                            .append($('<th>').addClass('picker-switch').attr('data-action', 'pickerSwitch').attr('colspan', (options.calendarWeeks ? '6' : '5')))
216                            .append($('<th>').addClass('next').attr('data-action', 'next')
217                                .append($('<span>').addClass(options.icons.next))
218                                )
219                            ),
220                    contTemplate = $('<tbody>')
221                        .append($('<tr>')
222                            .append($('<td>').attr('colspan', (options.calendarWeeks ? '8' : '7')))
223                            );
224
225                return [
226                    $('<div>').addClass('datepicker-days')
227                        .append($('<table>').addClass('table-condensed')
228                            .append(headTemplate)
229                            .append($('<tbody>'))
230                            ),
231                    $('<div>').addClass('datepicker-months')
232                        .append($('<table>').addClass('table-condensed')
233                            .append(headTemplate.clone())
234                            .append(contTemplate.clone())
235                            ),
236                    $('<div>').addClass('datepicker-years')
237                        .append($('<table>').addClass('table-condensed')
238                            .append(headTemplate.clone())
239                            .append(contTemplate.clone())
240                            ),
241                    $('<div>').addClass('datepicker-decades')
242                        .append($('<table>').addClass('table-condensed')
243                            .append(headTemplate.clone())
244                            .append(contTemplate.clone())
245                            )
246                ];
247            },
248
249            getTimePickerMainTemplate = function () {
250                var topRow = $('<tr>'),
251                    middleRow = $('<tr>'),
252                    bottomRow = $('<tr>');
253
254                if (isEnabled('h')) {
255                    topRow.append($('<td>')
256                        .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.incrementHour}).addClass('btn').attr('data-action', 'incrementHours')
257                            .append($('<span>').addClass(options.icons.up))));
258                    middleRow.append($('<td>')
259                        .append($('<span>').addClass('timepicker-hour').attr({'data-time-component':'hours', 'title': options.tooltips.pickHour}).attr('data-action', 'showHours')));
260                    bottomRow.append($('<td>')
261                        .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.decrementHour}).addClass('btn').attr('data-action', 'decrementHours')
262                            .append($('<span>').addClass(options.icons.down))));
263                }
264                if (isEnabled('m')) {
265                    if (isEnabled('h')) {
266                        topRow.append($('<td>').addClass('separator'));
267                        middleRow.append($('<td>').addClass('separator').html(':'));
268                        bottomRow.append($('<td>').addClass('separator'));
269                    }
270                    topRow.append($('<td>')
271                        .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.incrementMinute}).addClass('btn').attr('data-action', 'incrementMinutes')
272                            .append($('<span>').addClass(options.icons.up))));
273                    middleRow.append($('<td>')
274                        .append($('<span>').addClass('timepicker-minute').attr({'data-time-component': 'minutes', 'title': options.tooltips.pickMinute}).attr('data-action', 'showMinutes')));
275                    bottomRow.append($('<td>')
276                        .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.decrementMinute}).addClass('btn').attr('data-action', 'decrementMinutes')
277                            .append($('<span>').addClass(options.icons.down))));
278                }
279                if (isEnabled('s')) {
280                    if (isEnabled('m')) {
281                        topRow.append($('<td>').addClass('separator'));
282                        middleRow.append($('<td>').addClass('separator').html(':'));
283                        bottomRow.append($('<td>').addClass('separator'));
284                    }
285                    topRow.append($('<td>')
286                        .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.incrementSecond}).addClass('btn').attr('data-action', 'incrementSeconds')
287                            .append($('<span>').addClass(options.icons.up))));
288                    middleRow.append($('<td>')
289                        .append($('<span>
289').addClass('timepicker-second').attr({'data-time-component': 'seconds', 'title': options.tooltips.pickSecond}).attr('data-action', 'showSeconds')));
290                    bottomRow.append($('<td>')
291                        .append($('<a>').attr({href: '#', tabindex: '-1', 'title': options.tooltips.decrementSecond}).addClass('btn').attr('data-action', 'decrementSeconds')
292                            .append($('<span>').addClass(options.icons.down))));
293                }
294
295                if (!use24Hours) {
296                    topRow.append($('<td>').addClass('separator'));
297                    middleRow.append($('<td>')
298                        .append($('<button>').addClass('btn btn-primary btn-round').attr({'data-action': 'togglePeriod', tabindex: '-1', 'title': options.tooltips.togglePeriod})));
299                    bottomRow.append($('<td>').addClass('separator'));
300                }
301
302                return $('<div>').addClass('timepicker-picker')
303                    .append($('<table>').addClass('table-condensed')
304                        .append([topRow, middleRow, bottomRow]));
305            },
306
307            getTimePickerTemplate = function () {
308                var hoursView = $('<div>').addClass('timepicker-hours')
309                        .append($('<table>').addClass('table-condensed')),
310                    minutesView = $('<div>').addClass('timepicker-minutes')
311                        .append($('<table>').addClass('table-condensed')),
312                    secondsView = $('<div>').addClass('timepicker-seconds')
313                        .append($('<table>').addClass('table-condensed')),
314                    ret = [getTimePickerMainTemplate()];
315
316                if (isEnabled('h')) {
317                    ret.push(hoursView);
318                }
319                if (isEnabled('m')) {
320                    ret.push(minutesView);
321                }
322                if (isEnabled('s')) {
323                    ret.push(secondsView);
324                }
325
326                return ret;
327            },
328
329            getToolbar = function () {
330                var row = [];
331                if (options.showTodayButton) {
332                    row.push($('<td>').append($('<a>').attr({'data-action':'today', 'title': options.tooltips.today}).append($('<span>').addClass(options.icons.today))));
333                }
334                if (!options.sideBySide && hasDate() && hasTime()) {
335                    row.push($('<td>').append($('<a>').attr({'data-action':'togglePicker', 'title': options.tooltips.selectTime}).append($('<span>').addClass(options.icons.time))));
336                }
337                if (options.showClear) {
338                    row.push($('<td>').append($('<a>').attr({'data-action':'clear', 'title': options.tooltips.clear}).append($('<span>').addClass(options.icons.clear))));
339                }
340                if (options.showClose) {
341                    row.push($('<td>').append($('<a>').attr({'data-action':'close', 'title': options.tooltips.close}).append($('<span>').addClass(options.icons.close))));
342                }
343                return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row)));
344            },
345
346            getTemplate = function () {
347                var template = $('<div>').addClass('bootstrap-datetimepicker-widget dropdown-menu'),
348                    dateView = $('<div>').addClass('datepicker').append(getDatePickerTemplate()),
349                    timeView = $('<div>').addClass('timepicker').append(getTimePickerTemplate()),
350                    content = $('<ul>').addClass('list-unstyled'),
351                    toolbar = $('<li>').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar());
352
353                if (options.inline) {
354                    template.removeClass('dropdown-menu');
355                }
356
357                if (use24Hours) {
358                    template.addClass('usetwentyfour');
359                }
360                if (isEnabled('s') && !use24Hours) {
361                    template.addClass('wider');
362                }
363
364                if (options.sideBySide && hasDate() && hasTime()) {
365                    template.addClass('timepicker-sbs');
366                    if (options.toolbarPlacement === 'top') {
367                        template.append(toolbar);
368                    }
369                    template.append(
370                        $('<div>').addClass('row')
371                            .append(dateView.addClass('col-md-6'))
372                            .append(timeView.addClass('col-md-6'))
373                    );
374                    if (options.toolbarPlacement === 'bottom') {
375                        template.append(toolbar);
376                    }
377                    return template;
378                }
379
380                if (options.toolbarPlacement === 'top') {
381                    content.append(toolbar);
382                }
383                if (hasDate()) {
384                    content.append($('<li>').addClass((options.collapse && hasTime() ? 'collapse in' : '')).append(dateView));
385                }
386                if (options.toolbarPlacement === 'default') {
387                    content.append(toolbar);
388                }
389                if (hasTime()) {
390                    content.append($('<li>').addClass((options.collapse && hasDate() ? 'collapse' : '')).append(timeView));
391                }
392                if (options.toolbarPlacement === 'bottom') {
393                    content.append(toolbar);
394                }
395                return template.append(content);
396            },
397
398            dataToOptions = function () {
399                var eData,
400                    dataOptions = {};
401
402                if (element.is('input') || options.inline) {
403                    eData = element.data();
404                } else {
405                    eData = element.find('input').data();
406                }
407
408                if (eData.dateOptions && eData.dateOptions instanceof Object) {
409                    dataOptions = $.extend(true, dataOptions, eData.dateOptions);
410                }
411
412                $.each(options, function (key) {
413                    var attributeName = 'date' + key.charAt(0).toUpperCase() + key.slice(1);
414                    if (eData[attributeName] !== undefined) {
415                        dataOptions[key] = eData[attributeName];
416                    }
417                });
418                return dataOptions;
419            },
420
421            place = function () {
422                var position = (component || element).position(),
423                    offset = (component || element).offset(),
424                    vertical = options.widgetPositioning.vertical,
425                    horizontal = options.widgetPositioning.horizontal,
426                    parent;
427
428                if (options.widgetParent) {
429                    parent = options.widgetParent.append(widget);
430                } else if (element.is('input')) {
431                    parent = element.after(widget).parent();
432                } else if (options.inline) {
433                    parent = element.append(widget);
434                    return;
435                } else {
436                    parent = element;
437                    element.children().first().after(widget);
438                }
439
440                // Top and bottom logic
441                if (vertical === 'auto') {
442                    if (offset.top + widget.height() * 1.5 >= $(window).height() + $(window).scrollTop() &&
443                        widget.height() + element.outerHeight() < offset.top) {
444                        vertical = 'top';
445                    } else {
446                        vertical = 'bottom';
447                    }
448                }
449
450                // Left and right logic
451                if (horizontal === 'auto') {
452                    if (parent.width() < offset.left + widget.outerWidth() / 2 &&
453                        offset.left + widget.outerWidth() > $(window).width()) {
454                        horizontal = 'right';
455                    } else {
456                        horizontal = 'left';
457                    }
458                }
459
460                if (vertical === 'top') {
461                    widget.addClass('top').removeClass('bottom');
462                } else {
463                    widget.addClass('bottom').removeClass('top');
464                }
465
466                if (horizontal === 'right') {
467                    widget.addClass('pull-right');
468                } else {
469                    widget.removeClass('pull-right');
470                }
471
472                // find the first parent element that has a relative css positioning
473                if (parent.css('position') !== 'relative') {
474                    parent = parent.parents().filter(function () {
475                        return $(this).css('position') === 'relative';
476                    }).first();
477                }
478
479                if (parent.length === 0) {
480                    throw new Error('datetimepicker component should be placed within a relative positioned container');
481                }
482
483
484
485                widget.css({
486                    top: vertical === 'top' ? 'auto' : position.top + element.outerHeight(),
487                    bottom: vertical === 'top' ? position.top + element.outerHeight() : 'auto',
488                    left: horizontal === 'left' ? (parent === element ? 0 : position.left) : 'auto',
489                    right: horizontal === 'left' ? 'auto' : parent.outerWidth() - element.outerWidth() - (parent === element ? 0 : position.left)
490                });
491
492                // Creative Tim Changes - we add after 180 ms the ".open" class, in this way the animations will be the same with the other dropdowns from the
493                setTimeout(function(){
494                    widget.addClass('open');
495                }, 180);
496
497            },
498
499            notifyEvent = function (e) {
500                if (e.type === 'dp.change' && ((e.date && e.date.isSame(e.oldDate)) || (!e.date && !e.oldDate))) {
501                    return;
502                }
503                element.trigger(e);
504            },
505
506            viewUpdate = function (e) {
507                if (e === 'y') {
508                    e = 'YYYY';
509                }
510                notifyEvent({
511                    type: 'dp.update',
512                    change: e,
513                    viewDate: viewDate.clone()
514                });
515            },
516
517            showMode = function (dir) {
518                if (!widget) {
519                    return;
520                }
521                if (dir) {
522                    currentViewMode = Math.max(minViewModeNumber, Math.min(3, currentViewMode + dir));
523                }
524                widget.find('.datepicker > div').hide().filter('.datepicker-' + datePickerModes[currentViewMode].clsName).show();
525            },
526
527            fillDow = function () {
528                var row = $('<tr>'),
529                    currentDate = viewDate.clone().startOf('w').startOf('d');
530
531                if (options.calendarWeeks === true) {
532                    row.append($('<th>').addClass('cw').text('#'));
533                }
534
535                while (currentDate.isBefore(viewDate.clone().endOf('w'))) {
536                    row.append($('<th>').addClass('dow').text(currentDate.format('dd')));
537                    currentDate.add(1, 'd');
538                }
539                widget.find('.datepicker-days thead').append(row);
540            },
541
542            isInDisabledDates = function (testDate) {
543                return options.disabledDates[testDate.format('YYYY-MM-DD')] === true;
544            },
545
546            isInEnabledDates = function (testDate) {
547                return options.enabledDates[testDate.format('YYYY-MM-DD')] === true;
548            },
549
550            isInDisabledHours = function (testDate) {
551                return options.disabledHours[testDate.format('H')] === true;
552            },
553
554            isInEnabledHours = function (testDate) {
555                return options.enabledHours[testDate.format('H')] === true;
556            },
557
558            isValid = function (targetMoment, granularity) {
559                if (!targetMoment.isValid()) {
560                    return false;
561                }
562                if (options.disabledDates && granularity === 'd' && isInDisabledDates(targetMoment)) {
563                    return false;
564                }
565                if (options.enabledDates && granularity === 'd' && !isInEnabledDates(targetMoment)) {
566                    return false;
567                }
568                if (options.minDate && targetMoment.isBefore(options.minDate, granularity)) {
569                    return false;
570                }
571                if (options.maxDate && targetMoment.isAfter(options.maxDate, granularity)) {
572                    return false;
573                }
574                if (options.daysOfWeekDisabled && granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) {
575                    return false;
576                }
577                if (options.disabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && isInDisabledHours(targetMoment)) {
578                    return false;
579                }
580                if (options.enabledHours && (granularity === 'h' || granularity === 'm' || granularity === 's') && !isInEnabledHours(targetMoment)) {
581                    return false;
582                }
583                if (options.disabledTimeIntervals && (granularity === 'h' || granularity === 'm' || granularity === 's')) {
584                    var found = false;
585                    $.each(options.disabledTimeIntervals, function () {
586                        if (targetMoment.isBetween(this[0], this[1])) {
587                            found = true;
588                            return false;
589                        }
590                    });
591                    if (found) {
592                        return false;
593                    }
594                }
595                return true;
596            },
597
598            fillMonths = function () {
599                var spans = [],
600                    monthsShort = viewDate.clone().startOf('y').startOf('d');
601                while (monthsShort.isSame(viewDate, 'y')) {
602                    spans.push($('<span>').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM')));
603                    monthsShort.add(1, 'M');
604                }
605                widget.find('.datepicker-months td').empty().append(spans);
606            },
607
608            updateMonths = function () {
609                var monthsView = widget.find('.datepicker-months'),
610                    monthsViewHeader = monthsView.find('th'),
611                    months = monthsView.find('tbody').find('span');
612
613                monthsViewHeader.eq(0).find('span').attr('title', options.tooltips.prevYear);
614                monthsViewHeader.eq(1).attr('title', options.tooltips.selectYear);
615                monthsViewHeader.eq(2).find('span').attr('title', options.tooltips.nextYear);
616
617                monthsView.find('.disabled').removeClass('disabled');
618
619                if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) {
620                    monthsViewHeader.eq(0).addClass('disabled');
621                }
622
623                monthsViewHeader.eq(1).text(viewDate.year());
624
625                if (!isValid(viewDate.clone().add(1, 'y'), 'y')) {
626                    monthsViewHeader.eq(2).addClass('disabled');
627                }
628
629                months.removeClass('active');
630                if (date.isSame(viewDate, 'y') && !unset) {
631                    months.eq(date.month()).addClass('active');
632                }
633
634                months.each(function (index) {
635                    if (!isValid(viewDate.clone().month(index), 'M')) {
636                        $(this).addClass('disabled');
637                    }
638                });
639            },
640
641            updateYears = function () {
642                var yearsView = widget.find('.datepicker-years'),
643                    yearsViewHeader = yearsView.find('th'),
644                    startYear = viewDate.clone().subtract(5, 'y'),
645                    endYear = viewDate.clone().add(6, 'y'),
646                    html = '';
647
648                yearsViewHeader.eq(0).find('span').attr('title', options.tooltips.prevDecade);
649                yearsViewHeader.eq(1).attr('title', options.tooltips.selectDecade);
650                yearsViewHeader.eq(2).find('span').attr('title', options.tooltips.nextDecade);
651
652                yearsView.find('.disabled').removeClass('disabled');
653
654                if (options.minDate && options.minDate.isAfter(startYear, 'y')) {
655                    yearsViewHeader.eq(0).addClass('disabled');
656                }
657
658                yearsViewHeader.eq(1).text(startYear.year() + '-' + endYear.year());
659
660                if (options.maxDate && options.maxDate.isBefore(endYear, 'y')) {
661                    yearsViewHeader.eq(2).addClass('disabled');
662                }
663
664                while (!startYear.isAfter(endYear, 'y')) {
665                    html += '<span data-action="selectYear" class="year' + (startYear.isSame(date, 'y') && !unset ? ' active' : '') + (!isValid(startYear, 'y') ? ' disabled' : '') + '">' + startYear.year() + '</span>';
666                    startYear.add(1, 'y');
667                }
668
669                yearsView.find('td').html(html);
670            },
671
672            updateDecades = function () {
673                var decadesView = widget.find('.datepicker-decades'),
674                    decadesViewHeader = decadesView.find('th'),
675                    startDecade = moment({y: viewDate.year() - (viewDate.year() % 100) - 1}),
676                    endDecade = startDecade.clone().add(100, 'y'),
677                    startedAt = startDecade.clone(),
678                    html = '';
679
680                decadesViewHeader.eq(0).find('span').attr('title', options.tooltips.prevCentury);
681                decadesViewHeader.eq(2).find('span').attr('title', options.tooltips.nextCentury);
682
683                decadesView.find('.disabled').removeClass('disabled');
684
685                if (startDecade.isSame(moment({y: 1900})) || (options.minDate && options.minDate.isAfter(startDecade, 'y'))) {
686                    decadesViewHeader.eq(0).addClass('disabled');
687                }
688
689                decadesViewHeader.eq(1).text(startDecade.year() + '-' + endDecade.year());
690
691                if (startDecade.isSame(moment({y: 2000})) || (options.maxDate && options.maxDate.isBefore(endDecade, 'y'))) {
692                    decadesViewHeader.eq(2).addClass('disabled');
693                }
694
695                while (!startDecade.isAfter(endDecade, 'y')) {
696                    html += '<span data-action="selectDecade" class="decade' + (startDecade.isSame(date, 'y') ? ' active' : '') +
697                        (!isValid(startDecade, 'y') ? ' disabled' : '') + '" data-selection="' + (startDecade.year() + 6) + '">' + (startDecade.year() + 1) + ' - ' + (startDecade.year() + 12) + '</span>';
698                    startDecade.add(12, 'y');
699                }
700                html += '<span></span><span></span><span></span>'; //push the dangling block over, at least this way it's even
701
702                decadesView.find('td').html(html);
703                decadesViewHeader.eq(1).text((startedAt.year() + 1) + '-' + (startDecade.year()));
704            },
705
706            fillDate = function () {
707                var daysView = widget.find('.datepicker-days'),
708                    daysViewHeader = daysView.find('th'),
709                    currentDate,
710                    html = [],
711                    row,
712                    clsName,
713                    i;
714
715                if (!hasDate()) {
716                    return;
717                }
718
719                daysViewHeader.eq(0).find('span').attr('title', options.tooltips.prevMonth);
720                daysViewHeader.eq(1).attr('title', options.tooltips.selectMonth);
721                daysViewHeader.eq(2).find('span').attr('title', options.tooltips.nextMonth);
722
723                daysView.find('.disabled').removeClass('disabled');
724                daysViewHeader.eq(1).text(viewDate.format(options.dayViewHeaderFormat));
725
726                if (!isValid(viewDate.clone().subtract(1, 'M'), 'M')) {
727                    daysViewHeader.eq(0).addClass('disabled');
728                }
729                if (!isValid(viewDate.clone().add(1, 'M'), 'M')) {
730                    daysViewHeader.eq(2).addClass('disabled');
731                }
732
733                currentDate = viewDate.clone().startOf('M').startOf('w').startOf('d');
734
735                for (i = 0; i < 42; i++) { //always display 42 days (should show 6 weeks)
736                    if (currentDate.weekday() === 0) {
737                        row = $('<tr>');
738                        if (options.calendarWeeks) {
739                            row.append('<td class="cw">' + currentDate.week() + '</td>');
740                        }
741                        html.push(row);
742                    }
743                    clsName = '';
744                    if (currentDate.isBefore(viewDate, 'M')) {
745                        clsName += ' old';
746                    }
747                    if (currentDate.isAfter(viewDate, 'M')) {
748                        clsName += ' new';
749                    }
750                    if (currentDate.isSame(date, 'd') && !unset) {
751                        clsName += ' active';
752                    }
753                    if (!isValid(currentDate, 'd')) {
754                        clsName += ' disabled';
755                    }
756                    if (currentDate.isSame(getMoment(), 'd')) {
757                        clsName += ' today';
758                    }
759                    if (currentDate.day() === 0 || currentDate.day() === 6) {
760                        clsName += ' weekend';
761                    }
762
763
764                    // Creative Tim - we added a div inside each td for design purposes
765
766                    row.append('<td data-action="selectDay" data-day="' + currentDate.format('L') + '" class="day' + clsName + '"><div>' + currentDate.date() + '</div></td>');
767                    currentDate.add(1, 'd');
768                }
769
770                daysView.find('tbody').empty().append(html);
771
772                updateMonths();
773
774                updateYears();
775
776                updateDecades();
777            },
778
779            fillHours = function () {
780                var table = widget.find('.timepicker-hours table'),
781                    currentHour = viewDate.clone().startOf('d'),
782                    html = [],
783                    row = $('<tr>');
784
785                if (viewDate.hour() > 11 && !use24Hours) {
786                    currentHour.hour(12);
787                }
788                while (currentHour.isSame(viewDate, 'd') && (use24Hours || (viewDate.hour() < 12 && currentHour.hour() < 12) || viewDate.hour() > 11)) {
789                    if (currentHour.hour() % 4 === 0) {
790                        row = $('<tr>');
791                        html.push(row);
792                    }
793
794                    // Creative Tim - we added a div inside each class minute for design purposes
795
796                    row.append('<td data-action="selectHour" class="hour' + (!isValid(currentHour, 'h') ? ' disabled' : '') + '"><div>' + currentHour.format(use24Hours ? 'HH' : 'hh') + '</div></td>');
797                    currentHour.add(1, 'h');
798                }
799                table.empty().append(html);
800            },
801
802            fillMinutes = function () {
803                var table = widget.find('.timepicker-minutes table'),
804                    currentMinute = viewDate.clone().startOf('h'),
805                    html = [],
806                    row = $('<tr>'),
807                    step = options.stepping === 1 ? 5 : options.stepping;
808
809                while (viewDate.isSame(currentMinute, 'h')) {
810                    if (currentMinute.minute() % (step * 4) === 0) {
811                        row = $('<tr>');
812                        html.push(row);
813                    }
814
815
816                    // Creative Tim - we added a div inside each class minute for design purposes
817
818                    row.append('<td data-action="selectMinute" class="minute' + (!isValid(currentMinute, 'm') ? ' disabled' : '') + '"><div>' + currentMinute.format('mm') + '</div></td>');
819                    currentMinute.add(step, 'm');
820                }
821                table.empty().append(html);
822            },
823
824            fillSeconds = function () {
825                var table = widget.find('.timepicker-seconds table'),
826                    currentSecond = viewDate.clone().startOf('m'),
827                    html = [],
828                    row = $('<tr>');
829
830                while (viewDate.isSame(currentSecond, 'm')) {
831                    if (currentSecond.second() % 20 === 0) {
832                        row = $('<tr>');
833                        html.push(row);
834                    }
835
836                    // Creative Tim - we added a div inside each class minute for design purposes
837
838                    row.append('<td data-action="selectSecond" class="second' + (!isValid(currentSecond, 's') ? ' disabled' : '') + '"><div>' + currentSecond.format('ss') + '</div></td>');
839                    currentSecond.add(5, 's');
840                }
841
842                table.empty().append(html);
843            },
844
845            fillTime = function () {
846                var toggle, newDate, timeComponents = widget.find('.timepicker span[data-time-component]');
847
848                if (!use24Hours) {
849                    toggle = widget.find('.timepicker [data-action=togglePeriod]');
850                    newDate = date.clone().add((date.hours() >= 12) ? -12 : 12, 'h');
851
852                    toggle.text(date.format('A'));
853
854                    if (isValid(newDate, 'h')) {
855                        toggle.removeClass('disabled');
856                    } else {
857                        toggle.addClass('disabled');
858                    }
859                }
860                timeComponents.filter('[data-time-component=hours]').text(date.format(use24Hours ? 'HH' : 'hh'));
861                timeComponents.filter('[data-time-component=minutes]').text(date.format('mm'));
862                timeComponents.filter('[data-time-component=seconds]').text(date.format('ss'));
863
864                fillHours();
865                fillMinutes();
866                fillSeconds();
867            },
868
869            update = function () {
870                if (!widget) {
871                    return;
872                }
873                fillDate();
874                fillTime();
875            },
876
877            setValue = function (targetMoment) {
878                var oldDate = unset ? null : date;
879
880                // case of calling setValue(null or false)
881                if (!targetMoment) {
882                    unset = true;
883                    input.val('');
884                    element.data('date', '');
885                    notifyEvent({
886                        type: 'dp.change',
887                        date: false,
888                        oldDate: oldDate
889                    });
890                    update();
891                    return;
892                }
893
894                targetMoment = targetMoment.clone().locale(options.locale);
895
896                if (options.stepping !== 1) {
897                    targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping) % 60).seconds(0);
898                }
899
900                if (isValid(targetMoment)) {
901                    date = targetMoment;
902                    viewDate = date.clone();
903                    input.val(date.format(actualFormat));
904                    element.data('date', date.format(actualFormat));
905                    unset = false;
906                    update();
907                    notifyEvent({
908                        type: 'dp.change',
909                        date: date.clone(),
910                        oldDate: oldDate
911                    });
912                } else {
913                    if (!options.keepInvalid) {
914                        input.val(unset ? '' : date.format(actualFormat));
915                    }
916                    notifyEvent({
917                        type: 'dp.error',
918                        date: targetMoment
919                    });
920                }
921            },
922
923            hide = function () {
924                ///<summary>Hides the widget. Possibly will emit dp.hide</summary>
925                var transitioning = false;
926                if (!widget) {
927                    return picker;
928                }
929                // Ignore event if in the middle of a picker transition
930                widget.find('.collapse').each(function () {
931                    var collapseData = $(this).data('collapse');
932                    if (collapseData && collapseData.transitioning) {
933                        transitioning = true;
934                        return false;
935                    }
936                    return true;
937                });
938                if (transitioning) {
939                    return picker;
940                }
941                if (component && component.hasClass('btn')) {
942                    component.toggleClass('active');
943                }
944
945
946                $(window).off('resize', place);
947                widget.off('click', '[data-action]');
948                widget.off('mousedown', false);
949
950                // Creative Tim Changes - we remove the ".open" class, then, fter 400 ms call the .hide() method, in this way the animations will be the same with the other dropdowns from the dashboard
951
952                widget.removeClass('open');
953
954                setTimeout(function(){
955                    widget.hide();
956
957                    widget.remove();
958                    widget = false;
959
960                    notifyEvent({
961                        type: 'dp.hide',
962                        date: date.clone()
963                    });
964
965                    input.blur();
966
967                    return picker;
968
969                }, 400);
970
971            },
972
973            clear = function () {
974                setValue(null);
975            },
976
977            /********************************************************************************
978             *
979             * Widget UI interaction functions
980             *
981             ********************************************************************************/
982            actions = {
983                next: function () {
984                    var navFnc = datePickerModes[currentViewMode].navFnc;
985                    viewDate.add(datePickerModes[currentViewMode].navStep, navFnc);
986                    fillDate();
987                    viewUpdate(navFnc);
988                },
989
990                previous: function () {
991                    var navFnc = datePickerModes[currentViewMode].navFnc;
992                    viewDate.subtract(datePickerModes[currentViewMode].navStep, navFnc);
993                    fillDate();
994                    viewUpdate(navFnc);
995                },
996
997                pickerSwitch: function () {
998                    showMode(1);
999                },
1000
1001                selectMonth: function (e) {
1002                    var month = $(e.target).closest('tbody').find('span').index($(e.target));
1003                    viewDate.month(month);
1004                    if (currentViewMode === minViewModeNumber) {
1005                        setValue(date.clone().year(viewDate.year()).month(viewDate.month()));
1006                        if (!options.inline) {
1007                            hide();
1008                        }
1009                    } else {
1010                        showMode(-1);
1011                        fillDate();
1012                    }
1013                    viewUpdate('M');
1014                },
1015
1016                selectYear: function (e) {
1017                    var year = parseInt($(e.target).text(), 10) || 0;
1018                    viewDate.year(year);
1019                    if (currentViewMode === minViewModeNumber) {
1020                        setValue(date.clone().year(viewDate.year()));
1021                        if (!options.inline) {
1022                            hide();
1023                        }
1024                    } else {
1025                        showMode(-1);
1026                        fillDate();
1027                    }
1028                    viewUpdate('YYYY');
1029                },
1030
1031                selectDecade: function (e) {
1032                    var year = parseInt($(e.target).data('selection'), 10) || 0;
1033                    viewDate.year(year);
1034                    if (currentViewMode === minViewModeNumber) {
1035                        setValue(date.clone().year(viewDate.year()));
1036                        if (!options.inline) {
1037                            hide();
1038                        }
1039                    } else {
1040                        showMode(-1);
1041                        fillDate();
1042                    }
1043                    viewUpdate('YYYY');
1044                },
1045
1046                selectDay: function (e) {
1047                    var day = viewDate.clone();
1048                    if ($(e.target).is('.old')) {
1049                        day.subtract(1, 'M');
1050                    }
1051                    if ($(e.target).is('.new')) {
1052                        day.add(1, 'M');
1053                    }
1054                    setValue(day.date(parseInt($(e.target).text(), 10)));
1055                    if (!hasTime() && !options.keepOpen && !options.inline) {
1056                        hide();
1057                    }
1058                },
1059
1060                incrementHours: function () {
1061                    var newDate = date.clone().add(1, 'h');
1062                    if (isValid(newDate, 'h')) {
1063                        setValue(newDate);
1064                    }
1065                },
1066
1067                incrementMinutes: function () {
1068                    var newDate = date.clone().add(options.stepping, 'm');
1069                    if (isValid(newDate, 'm')) {
1070                        setValue(newDate);
1071                    }
1072                },
1073
1074                incrementSeconds: function () {
1075                    var newDate = date.clone().add(1, 's');
1076                    if (isValid(newDate, 's')) {
1077                        setValue(newDate);
1078                    }
1079                },
1080
1081                decrementHours: function () {
1082                    var newDate = date.clone().subtract(1, 'h');
1083                    if (isValid(newDate, 'h')) {
1084                        setValue(newDate);
1085                    }
1086                },
1087
1088                decrementMinutes: function () {
1089                    var newDate = date.clone().subtract(options.stepping, 'm');
1090                    if (isValid(newDate, 'm')) {
1091                        setValue(newDate);
1092                    }
1093                },
1094
1095                decrementSeconds: function () {
1096                    var newDate = date.clone().subtract(1, 's');
1097                    if (isValid(newDate, 's')) {
1098                        setValue(newDate);
1099                    }
1100                },
1101
1102                togglePeriod: function () {
1103                    setValue(date.clone().add((date.hours() >= 12) ? -12 : 12, 'h'));
1104                },
1105
1106                togglePicker: function (e) {
1107                    var $this = $(e.target),
1108                        $parent = $this.closest('ul'),
1109                        expanded = $parent.find('.in'),
1110                        closed = $parent.find('.collapse:not(.in)'),
1111                        collapseData;
1112
1113                    if (expanded && expanded.length) {
1114                        collapseData = expanded.data('collapse');
1115                        if (collapseData && collapseData.transitioning) {
1116                            return;
1117                        }
1118                        if (expanded.collapse) { // if collapse plugin is available through bootstrap.js then use it
1119                            expanded.collapse('hide');
1120                            closed.collapse('show');
1121                        } else { // otherwise just toggle in class on the two views
1122                            expanded.removeClass('in');
1123                            closed.addClass('in');
1124                        }
1125                        if ($this.is('span')) {
1126                            $this.toggleClass(options.icons.time + ' ' + options.icons.date);
1127                        } else {
1128                            $this.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
1129                        }
1130
1131                        // NOTE: uncomment if toggled state will be restored in show()
1132                        //if (component) {
1133                        //    component.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
1134                        //}
1135                    }
1136                },
1137
1138                showPicker: function () {
1139                    widget.find('.timepicker > div:not(.timepicker-picker)').hide();
1140                    widget.find('.timepicker .timepicker-picker').show();
1141                },
1142
1143                showHours: function () {
1144                    widget.find('.timepicker .timepicker-picker').hide();
1145                    widget.find('.timepicker .timepicker-hours').show();
1146                },
1147
1148                showMinutes: function () {
1149                    widget.find('.timepicker .timepicker-picker').hide();
1150                    widget.find('.timepicker .timepicker-minutes').show();
1151                },
1152
1153                showSeconds: function () {
1154                    widget.find('.timepicker .timepicker-picker').hide();
1155                    widget.find('.timepicker .timepicker-seconds').show();
1156                },
1157
1158                selectHour: function (e) {
1159                    var hour = parseInt($(e.target).text(), 10);
1160
1161                    if (!use24Hours) {
1162                        if (date.hours() >= 12) {
1163                            if (hour !== 12) {
1164                                hour += 12;
1165                            }
1166                        } else {
1167                            if (hour === 12) {
1168                                hour = 0;
1169                            }
1170                        }
1171                    }
1172                    setValue(date.clone().hours(hour));
1173                    actions.showPicker.call(picker);
1174                },
1175
1176                selectMinute: function (e) {
1177                    setValue(date.clone().minutes(parseInt($(e.target).text(), 10)));
1178                    actions.showPicker.call(picker);
1179                },
1180
1181                selectSecond: function (e) {
1182                    setValue(date.clone().seconds(parseInt($(e.target).text(), 10)));
1183                    actions.showPicker.call(picker);
1184                },
1185
1186                clear: clear,
1187
1188                today: function () {
1189                    var todaysDate = getMoment();
1190                    if (isValid(todaysDate, 'd')) {
1191                        setValue(todaysDate);
1192                    }
1193                },
1194
1195                close: hide
1196            },
1197
1198            doAction = function (e) {
1199                if ($(e.currentTarget).is('.disabled')) {
1200                    return false;
1201                }
1202                actions[$(e.currentTarget).data('action')].apply(picker, arguments);
1203                return false;
1204            },
1205
1206            show = function () {
1207                ///<summary>Shows the widget. Possibly will emit dp.show and dp.change</summary>
1208                var currentMoment,
1209                    useCurrentGranularity = {
1210                        'year': function (m) {
1211                            return m.month(0).date(1).hours(0).seconds(0).minutes(0);
1212                        },
1213                        'month': function (m) {
1214                            return m.date(1).hours(0).seconds(0).minutes(0);
1215                        },
1216                        'day': function (m) {
1217                            return m.hours(0).seconds(0).minutes(0);
1218                        },
1219                        'hour': function (m) {
1220                            return m.seconds(0).minutes(0);
1221                        },
1222                        'minute': function (m) {
1223                            return m.seconds(0);
1224                        }
1225                    };
1226
1227                if (input.prop('disabled') || (!options.ignoreReadonly && input.prop('readonly')) || widget) {
1228                    return picker;
1229                }
1230                if (input.val() !== undefined && input.val().trim().length !== 0) {
1231                    setValue(parseInputDate(input.val().trim()));
1232                } else if (options.useCurrent && unset && ((input.is('input') && input.val().trim().length === 0) || options.inline)) {
1233                    currentMoment = getMoment();
1234                    if (typeof options.useCurrent === 'string') {
1235                        currentMoment = useCurrentGranularity[options.useCurrent](currentMoment);
1236                    }
1237                    setValue(currentMoment);
1238                }
1239
1240                widget = getTemplate();
1241
1242                fillDow();
1243                fillMonths();
1244
1245                widget.find('.timepicker-hours').hide();
1246                widget.find('.timepicker-minutes').hide();
1247                widget.find('.timepicker-seconds').hide();
1248
1249                update();
1250                showMode();
1251
1252                $(window).on('resize', place);
1253                widget.on('click', '[data-action]', doAction); // this handles clicks on the widget
1254                widget.on('mousedown', false);
1255
1256                if (component && component.hasClass('btn')) {
1257                    component.toggleClass('active');
1258                }
1259                widget.show();
1260
1261                place();
1262
1263
1264                if (options.focusOnShow && !input.is(':focus')) {
1265                    input.focus();
1266                }
1267
1268                notifyEvent({
1269                    type: 'dp.show'
1270                });
1271                return picker;
1272            },
1273
1274            toggle = function () {
1275                /// <summary>Shows or hides the widget</summary>
1276                return (widget ? hide() : show());
1277            },
1278
1279            parseInputDate = function (inputDate) {
1280                if (options.parseInputDate === undefined) {
1281                    if (moment.isMoment(inputDate) || inputDate instanceof Date) {
1282                        inputDate = moment(inputDate);
1283                    } else {
1284                        inputDate = getMoment(inputDate);
1285                    }
1286                } else {
1287                    inputDate = options.parseInputDate(inputDate);
1288                }
1289                inputDate.locale(options.locale);
1290                return inputDate;
1291            },
1292
1293            keydown = function (e) {
1294                var handler = null,
1295                    index,
1296                    index2,
1297                    pressedKeys = [],
1298                    pressedModifiers = {},
1299                    currentKey = e.which,
1300                    keyBindKeys,
1301                    allModifiersPressed,
1302                    pressed = 'p';
1303
1304                keyState[currentKey] = pressed;
1305
1306                for (index in keyState) {
1307                    if (keyState.hasOwnProperty(index) && keyState[index] === pressed) {
1308                        pressedKeys.push(index);
1309                        if (parseInt(index, 10) !== currentKey) {
1310                            pressedModifiers[index] = true;
1311                        }
1312                    }
1313                }
1314
1315                for (index in options.keyBinds) {
1316                    if (options.keyBinds.hasOwnProperty(index) && typeof (options.keyBinds[index]) === 'function') {
1317                        keyBindKeys = index.split(' ');
1318                        if (keyBindKeys.length === pressedKeys.length && keyMap[currentKey] === keyBindKeys[keyBindKeys.length - 1]) {
1319                            allModifiersPressed = true;
1320                            for (index2 = keyBindKeys.length - 2; index2 >= 0; index2--) {
1321                                if (!(keyMap[keyBindKeys[index2]] in pressedModifiers)) {
1322                                    allModifiersPressed = false;
1323                                    break;
1324                                }
1325                            }
1326                            if (allModifiersPressed) {
1327                                handler = options.keyBinds[index];
1328                                break;
1329                            }
1330                        }
1331                    }
1332                }
1333
1334                if (handler) {
1335                    handler.call(picker, widget);
1336                    e.stopPropagation();
1337                    e.preventDefault();
1338                }
1339            },
1340
1341            keyup = function (e) {
1342                keyState[e.which] = 'r';
1343                e.stopPropagation();
1344                e.preventDefault();
1345            },
1346
1347            change = function (e) {
1348                var val = $(e.target).val().trim(),
1349                    parsedDate = val ? parseInputDate(val) : null;
1350                setValue(parsedDate);
1351                e.stopImmediatePropagation();
1352                return false;
1353            },
1354
1355            attachDatePickerElementEvents = function () {
1356                input.on({
1357                    'change': change,
1358                    'blur': options.debug ? '' : hide,
1359                    'keydown': keydown,
1360                    'keyup': keyup,
1361                    'focus': options.allowInputToggle ? show : ''
1362                });
1363
1364                if (element.is('input')) {
1365                    input.on({
1366                        'focus': show
1367                    });
1368                } else if (component) {
1369                    component.on('click', toggle);
1370                    component.on('mousedown', false);
1371                }
1372            },
1373
1374            detachDatePickerElementEvents = function () {
1375                input.off({
1376                    'change': change,
1377                    'blur': blur,
1378                    'keydown': keydown,
1379                    'keyup': keyup,
1380                    'focus': options.allowInputToggle ? hide : ''
1381                });
1382
1383                if (element.is('input')) {
1384                    input.off({
1385                        'focus': show
1386                    });
1387                } else if (component) {
1388                    component.off('click', toggle);
1389                    component.off('mousedown', false);
1390                }
1391            },
1392
1393            indexGivenDates = function (givenDatesArray) {
1394                // Store given enabledDates and disabledDates as keys.
1395                // This way we can check their existence in O(1) time instead of looping through whole array.
1396                // (for example: options.enabledDates['2014-02-27'] === true)
1397                var givenDatesIndexed = {};
1398                $.each(givenDatesArray, function () {
1399                    var dDate = parseInputDate(this);
1400                    if (dDate.isValid()) {
1401                        givenDatesIndexed[dDate.format('YYYY-MM-DD')] = true;
1402                    }
1403                });
1404                return (Object.keys(givenDatesIndexed).length) ? givenDatesIndexed : false;
1405            },
1406
1407            indexGivenHours = function (givenHoursArray) {
1408                // Store given enabledHours and disabledHours as keys.
1409                // This way we can check their existence in O(1) time instead of looping through whole array.
1410                // (for example: options.enabledHours['2014-02-27'] === true)
1411                var givenHoursIndexed = {};
1412                $.each(givenHoursArray, function () {
1413                    givenHoursIndexed[this] = true;
1414                });
1415                return (Object.keys(givenHoursIndexed).length) ? givenHoursIndexed : false;
1416            },
1417
1418            initFormatting = function () {
1419                var format = options.format || 'L LT';
1420
1421                actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput) {
1422                    var newinput = date.localeData().longDateFormat(formatInput) || formatInput;
1423                    return newinput.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput2) { //temp fix for #740
1424                        return date.localeData().longDateFormat(formatInput2) || formatInput2;
1425                    });
1426                });
1427
1428
1429                parseFormats = options.extraFormats ? options.extraFormats.slice() : [];
1430                if (parseFormats.indexOf(format) < 0 && parseFormats.indexOf(actualFormat) < 0) {
1431                    parseFormats.push(actualFormat);
1432                }
1433
1434                use24Hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.replace(/\[.*?\]/g, '').indexOf('h') < 1);
1435
1436                if (isEnabled('y')) {
1437                    minViewModeNumber = 2;
1438                }
1439                if (isEnabled('M')) {
1440                    minViewModeNumber = 1;
1441                }
1442                if (isEnabled('d')) {
1443                    minViewModeNumber = 0;
1444                }
1445
1446                currentViewMode = Math.max(minViewModeNumber, currentViewMode);
1447
1448                if (!unset) {
1449                    setValue(date);
1450                }
1451            };
1452
1453        /********************************************************************************
1454         *
1455         * Public API functions
1456         * =====================
1457         *
1458         * Important: Do not expose direct references to private objects or the options
1459         * object to the outer world. Always return a clone when returning values or make
1460         * a clone when setting a private variable.
1461         *
1462         ********************************************************************************/
1463        picker.destroy = function () {
1464            ///<summary>Destroys the widget and removes all attached event listeners</summary>
1465            hide();
1466            detachDatePickerElementEvents();
1467            element.removeData('DateTimePicker');
1468            element.removeData('date');
1469        };
1470
1471        picker.toggle = toggle;
1472
1473        picker.show = show;
1474
1475        picker.hide = hide;
1476
1477        picker.disable = function () {
1478            ///<summary>Disables the input element, the component is attached to, by adding a disabled="true" attribute to it.
1479            ///If the widget was visible before that call it is hidden. Possibly emits dp.hide</summary>
1480            hide();
1481            if (component && component.hasClass('btn')) {
1482                component.addClass('disabled');
1483            }
1484            input.prop('disabled', true);
1485            return picker;
1486        };
1487
1488        picker.enable = function () {
1489            ///<summary>Enables the input element, the component is attached to, by removing disabled attribute from it.</summary>
1490            if (component && component.hasClass('btn')) {
1491                component.removeClass('disabled');
1492            }
1493            input.prop('disabled', false);
1494            return picker;
1495        };
1496
1497        picker.ignoreReadonly = function (ignoreReadonly) {
1498            if (arguments.length === 0) {
1499                return options.ignoreReadonly;
1500            }
1501            if (typeof ignoreReadonly !== 'boolean') {
1502                throw new TypeError('ignoreReadonly () expects a boolean parameter');
1503            }
1504            options.ignoreReadonly = ignoreReadonly;
1505            return picker;
1506        };
1507
1508        picker.options = function (newOptions) {
1509            if (arguments.length === 0) {
1510                return $.extend(true, {}, options);
1511            }
1512
1513            if (!(newOptions instanceof Object)) {
1514                throw new TypeError('options() options parameter should be an object');
1515            }
1516            $.extend(true, options, newOptions);
1517            $.each(options, function (key, value) {
1518                if (picker[key] !== undefined) {
1519                    picker[key](value);
1520                } else {
1521                    throw new TypeError('option ' + key + ' is not recognized!');
1522                }
1523            });
1524            return picker;
1525        };
1526
1527        picker.date = function (newDate) {
1528            ///<signature helpKeyword="$.fn.datetimepicker.date">
1529            ///<summary>Returns the component's model current date, a moment object or null if not set.</summary>
1530            ///<returns type="Moment">date.clone()</returns>
1531            ///</signature>
1532            ///<signature>
1533            ///<summary>Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.</summary>
1534            ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, Date, moment, null parameter.</param>
1535            ///</signature>
1536            if (arguments.length === 0) {
1537                if (unset) {
1538                    return null;
1539                }
1540                return date.clone();
1541            }
1542
1543            if (newDate !== null && typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) {
1544                throw new TypeError('date() parameter must be one of [null, string, moment or Date]');
1545            }
1546
1547            setValue(newDate === null ? null : parseInputDate(newDate));
1548            return picker;
1549        };
1550
1551        picker.format = function (newFormat) {
1552            ///<summary>test su</summary>
1553            ///<param name="newFormat">info about para</param>
1554            ///<returns type="string|boolean">returns foo</returns>
1555            if (arguments.length === 0) {
1556                return options.format;
1557            }
1558
1559            if ((typeof newFormat !== 'string') && ((typeof newFormat !== 'boolean') || (newFormat !== false))) {
1560                throw new TypeError('format() expects a sting or boolean:false parameter ' + newFormat);
1561            }
1562
1563            options.format = newFormat;
1564            if (actualFormat) {
1565                initFormatting(); // reinit formatting
1566            }
1567            return picker;
1568        };
1569
1570        picker.timeZone = function (newZone) {
1571            if (arguments.length === 0) {
1572                return options.timeZone;
1573            }
1574
1575            options.timeZone = newZone;
1576
1577            return picker;
1578        };
1579
1580        picker.dayViewHeaderFormat = function (newFormat) {
1581            if (arguments.length === 0) {
1582                return options.dayViewHeaderFormat;
1583            }
1584
1585            if (typeof newFormat !== 'string') {
1586                throw new TypeError('dayViewHeaderFormat() expects a string parameter');
1587            }
1588
1589            options.dayViewHeaderFormat = newFormat;
1590            return picker;
1591        };
1592
1593        picker.extraFormats = function (formats) {
1594            if (arguments.length === 0) {
1595                return options.extraFormats;
1596            }
1597
1598            if (formats !== false && !(formats instanceof Array)) {
1599                throw new TypeError('extraFormats() expects an array or false parameter');
1600            }
1601
1602            options.extraFormats = formats;
1603            if (parseFormats) {
1604                initFormatting(); // reinit formatting
1605            }
1606            return picker;
1607        };
1608
1609        picker.disabledDates = function (dates) {
1610            ///<signature helpKeyword="$.fn.datetimepicker.disabledDates">
1611            ///<summary>Returns an array with the currently set disabled dates on the component.</summary>
1612            ///<returns type="array">options.disabledDates</returns>
1613            ///</signature>
1614            ///<signature>
1615            ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
1616            ///options.enabledDates if such exist.</summary>
1617            ///<param name="dates" locid="$.fn.datetimepicker.disabledDates_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.
1617</param>
1618            ///</signature>
1619            if (arguments.length === 0) {
1620                return (options.disabledDates ? $.extend({}, options.disabledDates) : options.disabledDates);
1621            }
1622
1623            if (!dates) {
1624                options.disabledDates = false;
1625                update();
1626                return picker;
1627            }
1628            if (!(dates instanceof Array)) {
1629                throw new TypeError('disabledDates() expects an array parameter');
1630            }
1631            options.disabledDates = indexGivenDates(dates);
1632            options.enabledDates = false;
1633            update();
1634            return picker;
1635        };
1636
1637        picker.enabledDates = function (dates) {
1638            ///<signature helpKeyword="$.fn.datetimepicker.enabledDates">
1639            ///<summary>Returns an array with the currently set enabled dates on the component.</summary>
1640            ///<returns type="array">options.enabledDates</returns>
1641            ///</signature>
1642            ///<signature>
1643            ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledDates if such exist.</summary>
1644            ///<param name="dates" locid="$.fn.datetimepicker.enabledDates_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
1645            ///</signature>
1646            if (arguments.length === 0) {
1647                return (options.enabledDates ? $.extend({}, options.enabledDates) : options.enabledDates);
1648            }
1649
1650            if (!dates) {
1651                options.enabledDates = false;
1652                update();
1653                return picker;
1654            }
1655            if (!(dates instanceof Array)) {
1656                throw new TypeError('enabledDates() expects an array parameter');
1657            }
1658            options.enabledDates = indexGivenDates(dates);
1659            options.disabledDates = false;
1660            update();
1661            return picker;
1662        };
1663
1664        picker.daysOfWeekDisabled = function (daysOfWeekDisabled) {
1665            if (arguments.length === 0) {
1666                return options.daysOfWeekDisabled.splice(0);
1667            }
1668
1669            if ((typeof daysOfWeekDisabled === 'boolean') && !daysOfWeekDisabled) {
1670                options.daysOfWeekDisabled = false;
1671                update();
1672                return picker;
1673            }
1674
1675            if (!(daysOfWeekDisabled instanceof Array)) {
1676                throw new TypeError('daysOfWeekDisabled() expects an array parameter');
1677            }
1678            options.daysOfWeekDisabled = daysOfWeekDisabled.reduce(function (previousValue, currentValue) {
1679                currentValue = parseInt(currentValue, 10);
1680                if (currentValue > 6 || currentValue < 0 || isNaN(currentValue)) {
1681                    return previousValue;
1682                }
1683                if (previousValue.indexOf(currentValue) === -1) {
1684                    previousValue.push(currentValue);
1685                }
1686                return previousValue;
1687            }, []).sort();
1688            if (options.useCurrent && !options.keepInvalid) {
1689                var tries = 0;
1690                while (!isValid(date, 'd')) {
1691                    date.add(1, 'd');
1692                    if (tries === 7) {
1693                        throw 'Tried 7 times to find a valid date';
1694                    }
1695                    tries++;
1696                }
1697                setValue(date);
1698            }
1699            update();
1700            return picker;
1701        };
1702
1703        picker.maxDate = function (maxDate) {
1704            if (arguments.length === 0) {
1705                return options.maxDate ? options.maxDate.clone() : options.maxDate;
1706            }
1707
1708            if ((typeof maxDate === 'boolean') && maxDate === false) {
1709                options.maxDate = false;
1710                update();
1711                return picker;
1712            }
1713
1714            if (typeof maxDate === 'string') {
1715                if (maxDate === 'now' || maxDate === 'moment') {
1716                    maxDate = getMoment();
1717                }
1718            }
1719
1720            var parsedDate = parseInputDate(maxDate);
1721
1722            if (!parsedDate.isValid()) {
1723                throw new TypeError('maxDate() Could not parse date parameter: ' + maxDate);
1724            }
1725            if (options.minDate && parsedDate.isBefore(options.minDate)) {
1726                throw new TypeError('maxDate() date parameter is before options.minDate: ' + parsedDate.format(actualFormat));
1727            }
1728            options.maxDate = parsedDate;
1729            if (options.useCurrent && !options.keepInvalid && date.isAfter(maxDate)) {
1730                setValue(options.maxDate);
1731            }
1732            if (viewDate.isAfter(parsedDate)) {
1733                viewDate = parsedDate.clone().subtract(options.stepping, 'm');
1734            }
1735            update();
1736            return picker;
1737        };
1738
1739        picker.minDate = function (minDate) {
1740            if (arguments.length === 0) {
1741                return options.minDate ? options.minDate.clone() : options.minDate;
1742            }
1743
1744            if ((typeof minDate === 'boolean') && minDate === false) {
1745                options.minDate = false;
1746                update();
1747                return picker;
1748            }
1749
1750            if (typeof minDate === 'string') {
1751                if (minDate === 'now' || minDate === 'moment') {
1752                    minDate = getMoment();
1753                }
1754            }
1755
1756            var parsedDate = parseInputDate(minDate);
1757
1758            if (!parsedDate.isValid()) {
1759                throw new TypeError('minDate() Could not parse date parameter: ' + minDate);
1760            }
1761            if (options.maxDate && parsedDate.isAfter(options.maxDate)) {
1762                throw new TypeError('minDate() date parameter is after options.maxDate: ' + parsedDate.format(actualFormat));
1763            }
1764            options.minDate = parsedDate;
1765            if (options.useCurrent && !options.keepInvalid && date.isBefore(minDate)) {
1766                setValue(options.minDate);
1767            }
1768            if (viewDate.isBefore(parsedDate)) {
1769                viewDate = parsedDate.clone().add(options.stepping, 'm');
1770            }
1771            update();
1772            return picker;
1773        };
1774
1775        picker.defaultDate = function (defaultDate) {
1776            ///<signature helpKeyword="$.fn.datetimepicker.defaultDate">
1777            ///<summary>Returns a moment with the options.defaultDate option configuration or false if not set</summary>
1778            ///<returns type="Moment">date.clone()</returns>
1779            ///</signature>
1780            ///<signature>
1781            ///<summary>Will set the picker's inital date. If a boolean:false value is passed the options.defaultDate parameter is cleared.</summary>
1782            ///<param name="defaultDate" locid="$.fn.datetimepicker.defaultDate_p:defaultDate">Takes a string, Date, moment, boolean:false</param>
1783            ///</signature>
1784            if (arguments.length === 0) {
1785                return options.defaultDate ? options.defaultDate.clone() : options.defaultDate;
1786            }
1787            if (!defaultDate) {
1788                options.defaultDate = false;
1789                return picker;
1790            }
1791
1792            if (typeof defaultDate === 'string') {
1793                if (defaultDate === 'now' || defaultDate === 'moment') {
1794                    defaultDate = getMoment();
1795                }
1796            }
1797
1798            var parsedDate = parseInputDate(defaultDate);
1799            if (!parsedDate.isValid()) {
1800                throw new TypeError('defaultDate() Could not parse date parameter: ' + defaultDate);
1801            }
1802            if (!isValid(parsedDate)) {
1803                throw new TypeError('defaultDate() date passed is invalid according to component setup validations');
1804            }
1805
1806            options.defaultDate = parsedDate;
1807
1808            if ((options.defaultDate && options.inline) || input.val().trim() === '') {
1809                setValue(options.defaultDate);
1810            }
1811            return picker;
1812        };
1813
1814        picker.locale = function (locale) {
1815            if (arguments.length === 0) {
1816                return options.locale;
1817            }
1818
1819            if (!moment.localeData(locale)) {
1820                throw new TypeError('locale() locale ' + locale + ' is not loaded from moment locales!');
1821            }
1822
1823            options.locale = locale;
1824            date.locale(options.locale);
1825            viewDate.locale(options.locale);
1826
1827            if (actualFormat) {
1828                initFormatting(); // reinit formatting
1829            }
1830            if (widget) {
1831                hide();
1832                show();
1833            }
1834            return picker;
1835        };
1836
1837        picker.stepping = function (stepping) {
1838            if (arguments.length === 0) {
1839                return options.stepping;
1840            }
1841
1842            stepping = parseInt(stepping, 10);
1843            if (isNaN(stepping) || stepping < 1) {
1844                stepping = 1;
1845            }
1846            options.stepping = stepping;
1847            return picker;
1848        };
1849
1850        picker.useCurrent = function (useCurrent) {
1851            var useCurrentOptions = ['year', 'month', 'day', 'hour', 'minute'];
1852            if (arguments.length === 0) {
1853                return options.useCurrent;
1854            }
1855
1856            if ((typeof useCurrent !== 'boolean') && (typeof useCurrent !== 'string')) {
1857                throw new TypeError('useCurrent() expects a boolean or string parameter');
1858            }
1859            if (typeof useCurrent === 'string' && useCurrentOptions.indexOf(useCurrent.toLowerCase()) === -1) {
1860                throw new TypeError('useCurrent() expects a string parameter of ' + useCurrentOptions.join(', '));
1861            }
1862            options.useCurrent = useCurrent;
1863            return picker;
1864        };
1865
1866        picker.collapse = function (collapse) {
1867            if (arguments.length === 0) {
1868                return options.collapse;
1869            }
1870
1871            if (typeof collapse !== 'boolean') {
1872                throw new TypeError('collapse() expects a boolean parameter');
1873            }
1874            if (options.collapse === collapse) {
1875                return picker;
1876            }
1877            options.collapse = collapse;
1878            if (widget) {
1879                hide();
1880                show();
1881            }
1882            return picker;
1883        };
1884
1885        picker.icons = function (icons) {
1886            if (arguments.length === 0) {
1887                return $.extend({}, options.icons);
1888            }
1889
1890            if (!(icons instanceof Object)) {
1891                throw new TypeError('icons() expects parameter to be an Object');
1892            }
1893            $.extend(options.icons, icons);
1894            if (widget) {
1895                hide();
1896                show();
1897            }
1898            return picker;
1899        };
1900
1901        picker.tooltips = function (tooltips) {
1902            if (arguments.length === 0) {
1903                return $.extend({}, options.tooltips);
1904            }
1905
1906            if (!(tooltips instanceof Object)) {
1907                throw new TypeError('tooltips() expects parameter to be an Object');
1908            }
1909            $.extend(options.tooltips, tooltips);
1910            if (widget) {
1911                hide();
1912                show();
1913            }
1914            return picker;
1915        };
1916
1917        picker.useStrict = function (useStrict) {
1918            if (arguments.length === 0) {
1919                return options.useStrict;
1920            }
1921
1922            if (typeof useStrict !== 'boolean') {
1923                throw new TypeError('useStrict() expects a boolean parameter');
1924            }
1925            options.useStrict = useStrict;
1926            return picker;
1927        };
1928
1929        picker.sideBySide = function (sideBySide) {
1930            if (arguments.length === 0) {
1931                return options.sideBySide;
1932            }
1933
1934            if (typeof sideBySide !== 'boolean') {
1935                throw new TypeError('sideBySide() expects a boolean parameter');
1936            }
1937            options.sideBySide = sideBySide;
1938            if (widget) {
1939                hide();
1940                show();
1941            }
1942            return picker;
1943        };
1944
1945        picker.viewMode = function (viewMode) {
1946            if (arguments.length === 0) {
1947                return options.viewMode;
1948            }
1949
1950            if (typeof viewMode !== 'string') {
1951                throw new TypeError('viewMode() expects a string parameter');
1952            }
1953
1954            if (viewModes.indexOf(viewMode) === -1) {
1955                throw new TypeError('viewMode() parameter must be one of (' + viewModes.join(', ') + ') value');
1956            }
1957
1958            options.viewMode = viewMode;
1959            currentViewMode = Math.max(viewModes.indexOf(viewMode), minViewModeNumber);
1960
1961            showMode();
1962            return picker;
1963        };
1964
1965        picker.toolbarPlacement = function (toolbarPlacement) {
1966            if (arguments.length === 0) {
1967                return options.toolbarPlacement;
1968            }
1969
1970            if (typeof toolbarPlacement !== 'string') {
1971                throw new TypeError('toolbarPlacement() expects a string parameter');
1972            }
1973            if (toolbarPlacements.indexOf(toolbarPlacement) === -1) {
1974                throw new TypeError('toolbarPlacement() parameter must be one of (' + toolbarPlacements.join(', ') + ') value');
1975            }
1976            options.toolbarPlacement = toolbarPlacement;
1977
1978            if (widget) {
1979                hide();
1980                show();
1981            }
1982            return picker;
1983        };
1984
1985        picker.widgetPositioning = function (widgetPositioning) {
1986            if (arguments.length === 0) {
1987                return $.extend({}, options.widgetPositioning);
1988            }
1989
1990            if (({}).toString.call(widgetPositioning) !== '[object Object]') {
1991                throw new TypeError('widgetPositioning() expects an object variable');
1992            }
1993            if (widgetPositioning.horizontal) {
1994                if (typeof widgetPositioning.horizontal !== 'string') {
1995                    throw new TypeError('widgetPositioning() horizontal variable must be a string');
1996                }
1997                widgetPositioning.horizontal = widgetPositioning.horizontal.toLowerCase();
1998                if (horizontalModes.indexOf(widgetPositioning.horizontal) === -1) {
1999                    throw new TypeError('widgetPositioning() expects horizontal parameter to be one of (' + horizontalModes.join(', ') + ')');
2000                }
2001                options.widgetPositioning.horizontal = widgetPositioning.horizontal;
2002            }
2003            if (widgetPositioning.vertical) {
2004                if (typeof widgetPositioning.vertical !== 'string') {
2005                    throw new TypeError('widgetPositioning() vertical variable must be a string');
2006                }
2007                widgetPositioning.vertical = widgetPositioning.vertical.toLowerCase();
2008                if (verticalModes.indexOf(widgetPositioning.vertical) === -1) {
2009                    throw new TypeError('widgetPositioning() expects vertical parameter to be one of (' + verticalModes.join(', ') + ')');
2010                }
2011                options.widgetPositioning.vertical = widgetPositioning.vertical;
2012            }
2013            update();
2014            return picker;
2015        };
2016
2017        picker.calendarWeeks = function (calendarWeeks) {
2018            if (arguments.length === 0) {
2019                return options.calendarWeeks;
2020            }
2021
2022            if (typeof calendarWeeks !== 'boolean') {
2023                throw new TypeError('calendarWeeks() expects parameter to be a boolean value');
2024            }
2025
2026            options.calendarWeeks = calendarWeeks;
2027            update();
2028            return picker;
2029        };
2030
2031        picker.showTodayButton = function (showTodayButton) {
2032            if (arguments.length === 0) {
2033                return options.showTodayButton;
2034            }
2035
2036            if (typeof showTodayButton !== 'boolean') {
2037                throw new TypeError('showTodayButton() expects a boolean parameter');
2038            }
2039
2040            options.showTodayButton = showTodayButton;
2041            if (widget) {
2042                hide();
2043                show();
2044            }
2045            return picker;
2046        };
2047
2048        picker.showClear = function (showClear) {
2049            if (arguments.length === 0) {
2050                return options.showClear;
2051            }
2052
2053            if (typeof showClear !== 'boolean') {
2054                throw new TypeError('showClear() expects a boolean parameter');
2055            }
2056
2057            options.showClear = showClear;
2058            if (widget) {
2059                hide();
2060                show();
2061            }
2062            return picker;
2063        };
2064
2065        picker.widgetParent = function (widgetParent) {
2066            if (arguments.length === 0) {
2067                return options.widgetParent;
2068            }
2069
2070            if (typeof widgetParent === 'string') {
2071                widgetParent = $(widgetParent);
2072            }
2073
2074            if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof $))) {
2075                throw new TypeError('widgetParent() expects a string or a jQuery object parameter');
2076            }
2077
2078            options.widgetParent = widgetParent;
2079            if (widget) {
2080                hide();
2081                show();
2082            }
2083            return picker;
2084        };
2085
2086        picker.keepOpen = function (keepOpen) {
2087            if (arguments.length === 0) {
2088                return options.keepOpen;
2089            }
2090
2091            if (typeof keepOpen !== 'boolean') {
2092                throw new TypeError('keepOpen() expects a boolean parameter');
2093            }
2094
2095            options.keepOpen = keepOpen;
2096            return picker;
2097        };
2098
2099        picker.focusOnShow = function (focusOnShow) {
2100            if (arguments.length === 0) {
2101                return options.focusOnShow;
2102            }
2103
2104            if (typeof focusOnShow !== 'boolean') {
2105                throw new TypeError('focusOnShow() expects a boolean parameter');
2106            }
2107
2108            options.focusOnShow = focusOnShow;
2109            return picker;
2110        };
2111
2112        picker.inline = function (inline) {
2113            if (arguments.length === 0) {
2114                return options.inline;
2115            }
2116
2117            if (typeof inline !== 'boolean') {
2118                throw new TypeError('inline() expects a boolean parameter');
2119            }
2120
2121            options.inline = inline;
2122            return picker;
2123        };
2124
2125        picker.clear = function () {
2126            clear();
2127            return picker;
2128        };
2129
2130        picker.keyBinds = function (keyBinds) {
2131            options.keyBinds = keyBinds;
2132            return picker;
2133        };
2134
2135        picker.getMoment = function (d) {
2136            return getMoment(d);
2137        };
2138
2139        picker.debug = function (debug) {
2140            if (typeof debug !== 'boolean') {
2141                throw new TypeError('debug() expects a boolean parameter');
2142            }
2143
2144            options.debug = debug;
2145            return picker;
2146        };
2147
2148        picker.allowInputToggle = function (allowInputToggle) {
2149            if (arguments.length === 0) {
2150                return options.allowInputToggle;
2151            }
2152
2153            if (typeof allowInputToggle !== 'boolean') {
2154                throw new TypeError('allowInputToggle() expects a boolean parameter');
2155            }
2156
2157            options.allowInputToggle = allowInputToggle;
2158            return picker;
2159        };
2160
2161        picker.showClose = function (showClose) {
2162            if (arguments.length === 0) {
2163                return options.showClose;
2164            }
2165
2166            if (typeof showClose !== 'boolean') {
2167                throw new TypeError('showClose() expects a boolean parameter');
2168            }
2169
2170            options.showClose = showClose;
2171            return picker;
2172        };
2173
2174        picker.keepInvalid = function (keepInvalid) {
2175            if (arguments.length === 0) {
2176                return options.keepInvalid;
2177            }
2178
2179            if (typeof keepInvalid !== 'boolean') {
2180                throw new TypeError('keepInvalid() expects a boolean parameter');
2181            }
2182            options.keepInvalid = keepInvalid;
2183            return picker;
2184        };
2185
2186        picker.datepickerInput = function (datepickerInput) {
2187            if (arguments.length === 0) {
2188                return options.datepickerInput;
2189            }
2190
2191            if (typeof datepickerInput !== 'string') {
2192                throw new TypeError('datepickerInput() expects a string parameter');
2193            }
2194
2195            options.datepickerInput = datepickerInput;
2196            return picker;
2197        };
2198
2199        picker.parseInputDate = function (parseInputDate) {
2200            if (arguments.length === 0) {
2201                return options.parseInputDate;
2202            }
2203
2204            if (typeof parseInputDate !== 'function') {
2205                throw new TypeError('parseInputDate() sholud be as function');
2206            }
2207
2208            options.parseInputDate = parseInputDate;
2209
2210            return picker;
2211        };
2212
2213        picker.disabledTimeIntervals = function (disabledTimeIntervals) {
2214            ///<signature helpKeyword="$.fn.datetimepicker.disabledTimeIntervals">
2215            ///<summary>Returns an array with the currently set disabled dates on the component.</summary>
2216            ///<returns type="array">options.disabledTimeIntervals</returns>
2217            ///</signature>
2218            ///<signature>
2219            ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
2220            ///options.enabledDates if such exist.</summary>
2221            ///<param name="dates" locid="$.fn.datetimepicker.disabledTimeIntervals_p:dates">Takes an [ string or Date or moment ] of values and allows the user to select only from those days.</param>
2222            ///</signature>
2223            if (arguments.length === 0) {
2224                return (options.disabledTimeIntervals ? $.extend({}, options.disabledTimeIntervals) : options.disabledTimeIntervals);
2225            }
2226
2227            if (!disabledTimeIntervals) {
2228                options.disabledTimeIntervals = false;
2229                update();
2230                return picker;
2231            }
2232            if (!(disabledTimeIntervals instanceof Array)) {
2233                throw new TypeError('disabledTimeIntervals() expects an array parameter');
2234            }
2235            options.disabledTimeIntervals = disabledTimeIntervals;
2236            update();
2237            return picker;
2238        };
2239
2240        picker.disabledHours = function (hours) {
2241            ///<signature helpKeyword="$.fn.datetimepicker.disabledHours">
2242            ///<summary>Returns an array with the currently set disabled hours on the component.</summary>
2243            ///<returns type="array">options.disabledHours</returns>
2244            ///</signature>
2245            ///<signature>
2246            ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of
2247            ///options.enabledHours if such exist.</summary>
2248            ///<param name="hours" locid="$.fn.datetimepicker.disabledHours_p:hours">Takes an [ int ] of values and disallows the user to select only from those hours.</param>
2249            ///</signature>
2250            if (arguments.length === 0) {
2251                return (options.disabledHours ? $.extend({}, options.disabledHours) : options.disabledHours);
2252            }
2253
2254            if (!hours) {
2255                options.disabledHours = false;
2256                update();
2257                return picker;
2258            }
2259            if (!(hours instanceof Array)) {
2260                throw new TypeError('disabledHours() expects an array parameter');
2261            }
2262            options.disabledHours = indexGivenHours(hours);
2263            options.enabledHours = false;
2264            if (options.useCurrent && !options.keepInvalid) {
2265                var tries = 0;
2266                while (!isValid(date, 'h')) {
2267                    date.add(1, 'h');
2268                    if (tries === 24) {
2269                        throw 'Tried 24 times to find a valid date';
2270                    }
2271                    tries++;
2272                }
2273                setValue(date);
2274            }
2275            update();
2276            return picker;
2277        };
2278
2279        picker.enabledHours = function (hours) {
2280            ///<signature helpKeyword="$.fn.datetimepicker.enabledHours">
2281            ///<summary>Returns an array with the currently set enabled hours on the component.</summary>
2282            ///<returns type="array">options.enabledHours</returns>
2283            ///</signature>
2284            ///<signature>
2285            ///<summary>Setting this takes precedence over options.minDate, options.maxDate configuration. Also calling this function removes the configuration of options.disabledHours if such exist.</summary>
2286            ///<param name="hours" locid="$.fn.datetimepicker.enabledHours_p:hours">Takes an [ int ] of values and allows the user to select only from those hours.</param>
2287            ///</signature>
2288            if (arguments.length === 0) {
2289                return (options.enabledHours ? $.extend({}, options.enabledHours) : options.enabledHours);
2290            }
2291
2292            if (!hours) {
2293                options.enabledHours = false;
2294                update();
2295                return picker;
2296            }
2297            if (!(hours instanceof Array)) {
2298                throw new TypeError('enabledHours() expects an array parameter');
2299            }
2300            options.enabledHours = indexGivenHours(hours);
2301            options.disabledHours = false;
2302            if (options.useCurrent && !options.keepInvalid) {
2303                var tries = 0;
2304                while (!isValid(date, 'h')) {
2305                    date.add(1, 'h');
2306                    if (tries === 24) {
2307                        throw 'Tried 24 times to find a valid date';
2308                    }
2309                    tries++;
2310                }
2311                setValue(date);
2312            }
2313            update();
2314            return picker;
2315        };
2316
2317        picker.viewDate = function (newDate) {
2318            ///<signature helpKeyword="$.fn.datetimepicker.viewDate">
2319            ///<summary>Returns the component's model current viewDate, a moment object or null if not set.</summary>
2320            ///<returns type="Moment">viewDate.clone()</returns>
2321            ///</signature>
2322            ///<signature>
2323            ///<summary>Sets the components model current moment to it. Passing a null value unsets the components model current moment. Parsing of the newDate parameter is made using moment library with the options.format and options.useStrict components configuration.</summary>
2324            ///<param name="newDate" locid="$.fn.datetimepicker.date_p:newDate">Takes string, viewDate, moment, null parameter.</param>
2325            ///</signature>
2326            if (arguments.length === 0) {
2327                return viewDate.clone();
2328            }
2329
2330            if (!newDate) {
2331                viewDate = date.clone();
2332                return picker;
2333            }
2334
2335            if (typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) {
2336                throw new TypeError('viewDate() parameter must be one of [string, moment or Date]');
2337            }
2338
2339            viewDate = parseInputDate(newDate);
2340            viewUpdate();
2341            return picker;
2342        };
2343
2344        // initializing element and component attributes
2345        if (element.is('input')) {
2346            input = element;
2347        } else {
2348            input = element.find(options.datepickerInput);
2349            if (input.size() === 0) {
2350                input = element.find('input');
2351            } else if (!input.is('input')) {
2352                throw new Error('CSS class "' + options.datepickerInput + '" cannot be applied to non input element');
2353            }
2354        }
2355
2356        if (element.hasClass('input-group')) {
2357            // in case there is more then one 'input-group-addon' Issue #48
2358            if (element.find('.datepickerbutton').size() === 0) {
2359                component = element.find('.input-group-addon');
2360            } else {
2361                component = element.find('.datepickerbutton');
2362            }
2363        }
2364
2365        if (!options.inline && !input.is('input')) {
2366            throw new Error('Could not initialize DateTimePicker without an input element');
2367        }
2368
2369        // Set defaults for date here now instead of in var declaration
2370        date = getMoment();
2371        viewDate = date.clone();
2372
2373        $.extend(true, options, dataToOptions());
2374
2375        picker.options(options);
2376
2377        initFormatting();
2378
2379        attachDatePickerElementEvents();
2380
2381        if (input.prop('disabled')) {
2382            picker.disable();
2383        }
2384        if (input.is('input') && input.val().trim().length !== 0) {
2385            setValue(parseInputDate(input.val().trim()));
2386        }
2387        else if (options.defaultDate && input.attr('placeholder') 
2387=== undefined) {
2388            setValue(options.defaultDate);
2389        }
2390        if (options.inline) {
2391            show();
2392        }
2393        return picker;
2394    };
2395
2396    /********************************************************************************
2397     *
2398     * jQuery plugin constructor and defaults object
2399     *
2400     ********************************************************************************/
2401
2402    $.fn.datetimepicker = function (options) {
2403        return this.each(function () {
2404            var $this = $(this);
2405            if (!$this.data('DateTimePicker')) {
2406                // create a private copy of the defaults object
2407                options = $.extend(true, {}, $.fn.datetimepicker.defaults, options);
2408                $this.data('DateTimePicker', dateTimePicker($this, options));
2409            }
2410        });
2411    };
2412
2413    $.fn.datetimepicker.defaults = {
2414        timeZone: 'Etc/UTC',
2415        format: false,
2416        dayViewHeaderFormat: 'MMMM YYYY',
2417        extraFormats: false,
2418        stepping: 1,
2419        minDate: false,
2420        maxDate: false,
2421        useCurrent: true,
2422        collapse: true,
2423        locale: moment.locale(),
2424        defaultDate: false,
2425        disabledDates: false,
2426        enabledDates: false,
2427        icons: {
2428            time: 'glyphicon glyphicon-time',
2429            date: 'glyphicon glyphicon-calendar',
2430            up: 'glyphicon glyphicon-chevron-up',
2431            down: 'glyphicon glyphicon-chevron-down',
2432            previous: 'glyphicon glyphicon-chevron-left',
2433            next: 'glyphicon glyphicon-chevron-right',
2434            today: 'glyphicon glyphicon-screenshot',
2435            clear: 'glyphicon glyphicon-trash',
2436            close: 'glyphicon glyphicon-remove'
2437        },
2438        tooltips: {
2439            today: 'Go to today',
2440            clear: 'Clear selection',
2441            close: 'Close the picker',
2442            selectMonth: 'Select Month',
2443            prevMonth: 'Previous Month',
2444            nextMonth: 'Next Month',
2445            selectYear: 'Select Year',
2446            prevYear: 'Previous Year',
2447            nextYear: 'Next Year',
2448            selectDecade: 'Select Decade',
2449            prevDecade: 'Previous Decade',
2450            nextDecade: 'Next Decade',
2451            prevCentury: 'Previous Century',
2452            nextCentury: 'Next Century',
2453            pickHour: 'Pick Hour',
2454            incrementHour: 'Increment Hour',
2455            decrementHour: 'Decrement Hour',
2456            pickMinute: 'Pick Minute',
2457            incrementMinute: 'Increment Minute',
2458            decrementMinute: 'Decrement Minute',
2459            pickSecond: 'Pick Second',
2460            incrementSecond: 'Increment Second',
2461            decrementSecond: 'Decrement Second',
2462            togglePeriod: 'Toggle Period',
2463            selectTime: 'Select Time'
2464        },
2465        useStrict: false,
2466        sideBySide: false,
2467        daysOfWeekDisabled: false,
2468        calendarWeeks: false,
2469        viewMode: 'days',
2470        toolbarPlacement: 'default',
2471        showTodayButton: false,
2472        showClear: false,
2473        showClose: false,
2474        widgetPositioning: {
2475            horizontal: 'auto',
2476            vertical: 'auto'
2477        },
2478        widgetParent: null,
2479        ignoreReadonly: false,
2480        keepOpen: false,
2481        focusOnShow: true,
2482        inline: false,
2483        keepInvalid: false,
2484        datepickerInput: '.datepickerinput',
2485        keyBinds: {
2486            up: function (widget) {
2487                if (!widget) {
2488                    return;
2489                }
2490                var d = this.date() || this.getMoment();
2491                if (widget.find('.datepicker').is(':visible')) {
2492                    this.date(d.clone().subtract(7, 'd'));
2493                } else {
2494                    this.date(d.clone().add(this.stepping(), 'm'));
2495                }
2496            },
2497            down: function (widget) {
2498                if (!widget) {
2499                    this.show();
2500                    return;
2501                }
2502                var d = this.date() || this.getMoment();
2503                if (widget.find('.datepicker').is(':visible')) {
2504                    this.date(d.clone().add(7, 'd'));
2505                } else {
2506                    this.date(d.clone().subtract(this.stepping(), 'm'));
2507                }
2508            },
2509            'control up': function (widget) {
2510                if (!widget) {
2511                    return;
2512                }
2513                var d = this.date() || this.getMoment();
2514                if (widget.find('.datepicker').is(':visible')) {
2515                    this.date(d.clone().subtract(1, 'y'));
2516                } else {
2517                    this.date(d.clone().add(1, 'h'));
2518                }
2519            },
2520            'control down': function (widget) {
2521                if (!widget) {
2522                    return;
2523                }
2524                var d = this.date() || this.getMoment();
2525                if (widget.find('.datepicker').is(':visible')) {
2526                    this.date(d.clone().add(1, 'y'));
2527                } else {
2528                    this.date(d.clone().subtract(1, 'h'));
2529                }
2530            },
2531            left: function (widget) {
2532                if (!widget) {
2533                    return;
2534                }
2535                var d = this.date() || this.getMoment();
2536                if (widget.find('.datepicker').is(':visible')) {
2537                    this.date(d.clone().subtract(1, 'd'));
2538                }
2539            },
2540            right: function (widget) {
2541                if (!widget) {
2542                    return;
2543                }
2544                var d = this.date() || this.getMoment();
2545                if (widget.find('.datepicker').is(':visible')) {
2546                    this.date(d.clone().add(1, 'd'));
2547                }
2548            },
2549            pageUp: function (widget) {
2550                if (!widget) {
2551                    return;
2552                }
2553                var d = this.date() || this.getMoment();
2554                if (widget.find('.datepicker').is(':visible')) {
2555                    this.date(d.clone().subtract(1, 'M'));
2556                }
2557            },
2558            pageDown: function (widget) {
2559                if (!widget) {
2560                    return;
2561                }
2562                var d = this.date() || this.getMoment();
2563                if (widget.find('.datepicker').is(':visible')) {
2564                    this.date(d.clone().add(1, 'M'));
2565                }
2566            },
2567            enter: function () {
2568                this.hide();
2569            },
2570            escape: function () {
2571                this.hide();
2572            },
2573            //tab: function (widget) { //this break the flow of the form. disabling for now
2574            //    var toggle = widget.find('.picker-switch a[data-action="togglePicker"]');
2575            //    if(toggle.length > 0) toggle.click();
2576            //},
2577            'control space': function (widget) {
2578                if (widget.find('.timepicker').is(':visible')) {
2579                    widget.find('.btn[data-action="togglePeriod"]').click();
2580                }
2581            },
2582            t: function () {
2583                this.date(this.getMoment());
2584            },
2585            'delete': function () {
2586                this.clear();
2587            }
2588        },
2589        debug: false,
2590        allowInputToggle: false,
2591        disabledTimeIntervals: false,
2592        disabledHours: false,
2593        enabledHours: false,
2594        viewDate: false
2595    };
2596}));

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.