PageSourceSearch

https://pafikabupatenmanggaraibarat.org/cdn/boots/dist/js/bootstrap-datetimepicker.js

js pafikabupatenmanggaraibarat.org collected 2026-10-06 21:36:54 UTC 99,313 bytes, 2,444 lines download raw bytes

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

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.