You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@isis.apache.org by da...@apache.org on 2015/01/29 20:15:07 UTC

[03/18] isis git commit: ISIS-1012 Update bootstrap-datetimepicker to v4(final) and momentjs to 2.9.0

http://git-wip-us.apache.org/repos/asf/isis/blob/c054fd0c/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/datepicker/js/bootstrap-datetimepicker.js
----------------------------------------------------------------------
diff --git a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/datepicker/js/bootstrap-datetimepicker.js b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/datepicker/js/bootstrap-datetimepicker.js
index 9ffc26e..b912fa8 100644
--- a/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/datepicker/js/bootstrap-datetimepicker.js
+++ b/component/viewer/wicket/ui/src/main/java/org/apache/isis/viewer/wicket/ui/components/scalars/datepicker/js/bootstrap-datetimepicker.js
@@ -1,12 +1,12 @@
 /*
- //! version : 4.0.0-beta
+ //! version : 4.0.0
  =========================================================
  bootstrap-datetimejs
  https://github.com/Eonasdan/bootstrap-datetimepicker
  =========================================================
  The MIT License (MIT)
 
- Copyright (c) 2014 Jonathan Peterson
+ Copyright (c) 2015 Jonathan Peterson
 
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
@@ -50,49 +50,50 @@
     }
 
     var dateTimePicker = function (element, options) {
-            var picker = {},
-                date = moment(),
-                viewDate = date.clone(),
-                unset = true,
-                input,
-                component = false,
-                widget = false,
-                use24hours,
-                minViewModeNumber = 0,
-                actualFormat,
-                errored = false,
-                currentViewMode,
-                datePickerModes = [
-                    {
-                        clsName: 'days',
-                        navFnc: 'M',
-                        navStep: 1
-                    },
-                    {
-                        clsName: 'months',
-                        navFnc: 'y',
-                        navStep: 1
-                    },
-                    {
-                        clsName: 'years',
-                        navFnc: 'y',
-                        navStep: 10
-                    }
-                ],
-                viewModes = ['days', 'months', 'years'],
-                verticalModes = ['top', 'bottom', 'auto'],
-                horizontalModes = ['left', 'right', 'auto'],
-
-                /********************************************************************************
-                 *
-                 * Private functions
-                 *
-                 ********************************************************************************/
-                isEnabled = function (granularity) {
-                    if (typeof granularity !== 'string' || granularity.length > 1) {
-                        throw new TypeError('isEnabled expects a single character string parameter');
-                    }
-                    switch (granularity) {
+        var picker = {},
+            date = moment(),
+            viewDate = date.clone(),
+            unset = true,
+            input,
+            component = false,
+            widget = false,
+            use24Hours,
+            minViewModeNumber = 0,
+            actualFormat,
+            parseFormats,
+            currentViewMode,
+            datePickerModes = [
+                {
+                    clsName: 'days',
+                    navFnc: 'M',
+                    navStep: 1
+                },
+                {
+                    clsName: 'months',
+                    navFnc: 'y',
+                    navStep: 1
+                },
+                {
+                    clsName: 'years',
+                    navFnc: 'y',
+                    navStep: 10
+                }
+            ],
+            viewModes = ['days', 'months', 'years'],
+            verticalModes = ['top', 'bottom', 'auto'],
+            horizontalModes = ['left', 'right', 'auto'],
+            toolbarPlacements = ['default', 'top', 'bottom'],
+
+            /********************************************************************************
+             *
+             * Private functions
+             *
+             ********************************************************************************/
+            isEnabled = function (granularity) {
+                if (typeof granularity !== 'string' || granularity.length > 1) {
+                    throw new TypeError('isEnabled expects a single character string parameter');
+                }
+                switch (granularity) {
                     case 'y':
                         return actualFormat.indexOf('Y') !== -1;
                     case 'M':
@@ -108,1435 +109,1539 @@
                         return actualFormat.indexOf('s') !== -1;
                     default:
                         return false;
-                    }
-                },
+                }
+            },
 
-                hasTime = function () {
-                    return (isEnabled('h') || isEnabled('m') || isEnabled('s'));
-                },
+            hasTime = function () {
+                return (isEnabled('h') || isEnabled('m') || isEnabled('s'));
+            },
 
-                hasDate = function () {
-                    return (isEnabled('y') || isEnabled('M') || isEnabled('d'));
-                },
+            hasDate = function () {
+                return (isEnabled('y') || isEnabled('M') || isEnabled('d'));
+            },
 
-                getDatePickerTemplate = function () {
-                    var headTemplate = $('<thead>')
-                            .append($('<tr>')
-                                .append($('<th>').addClass('prev').attr('data-action', 'previous')
-                                    .append($('<span>').addClass(options.icons.previous))
-                                    )
-                                .append($('<th>').addClass('picker-switch').attr('data-action', 'pickerSwitch').attr('colspan', (options.calendarWeeks ? '6' : '5')))
-                                .append($('<th>').addClass('next').attr('data-action', 'next')
-                                    .append($('<span>').addClass(options.icons.next))
-                                    )
-                                ),
-                        contTemplate = $('<tbody>')
-                            .append($('<tr>')
-                                .append($('<td>').attr('colspan', (options.calendarWeeks ? '8' : '7')))
-                                );
-
-                    return [
-                        $('<div>').addClass('datepicker-days')
-                            .append($('<table>').addClass('table-condensed')
-                                .append(headTemplate)
-                                .append($('<tbody>'))
-                                ),
-                        $('<div>').addClass('datepicker-months')
-                            .append($('<table>').addClass('table-condensed')
-                                .append(headTemplate.clone())
-                                .append(contTemplate.clone())
-                                ),
-                        $('<div>').addClass('datepicker-years')
-                            .append($('<table>').addClass('table-condensed')
-                                .append(headTemplate.clone())
-                                .append(contTemplate.clone())
+            getDatePickerTemplate = function () {
+                var headTemplate = $('<thead>')
+                        .append($('<tr>')
+                            .append($('<th>').addClass('prev').attr('data-action', 'previous')
+                                .append($('<span>').addClass(options.icons.previous))
                                 )
-                    ];
-                },
-
-                getTimePickerMainTemplate = function () {
-                    var topRow = $('<tr>'),
-                        middleRow = $('<tr>'),
-                        bottomRow = $('<tr>');
-
+                            .append($('<th>').addClass('picker-switch').attr('data-action', 'pickerSwitch').attr('colspan', (options.calendarWeeks ? '6' : '5')))
+                            .append($('<th>').addClass('next').attr('data-action', 'next')
+                                .append($('<span>').addClass(options.icons.next))
+                                )
+                            ),
+                    contTemplate = $('<tbody>')
+                        .append($('<tr>')
+                            .append($('<td>').attr('colspan', (options.calendarWeeks ? '8' : '7')))
+                            );
+
+                return [
+                    $('<div>').addClass('datepicker-days')
+                        .append($('<table>').addClass('table-condensed')
+                            .append(headTemplate)
+                            .append($('<tbody>'))
+                            ),
+                    $('<div>').addClass('datepicker-months')
+                        .append($('<table>').addClass('table-condensed')
+                            .append(headTemplate.clone())
+                            .append(contTemplate.clone())
+                            ),
+                    $('<div>').addClass('datepicker-years')
+                        .append($('<table>').addClass('table-condensed')
+                            .append(headTemplate.clone())
+                            .append(contTemplate.clone())
+                            )
+                ];
+            },
+
+            getTimePickerMainTemplate = function () {
+                var topRow = $('<tr>'),
+                    middleRow = $('<tr>'),
+                    bottomRow = $('<tr>');
+
+                if (isEnabled('h')) {
+                    topRow.append($('<td>')
+                        .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementHours')
+                            .append($('<span>').addClass(options.icons.up))));
+                    middleRow.append($('<td>')
+                        .append($('<span>').addClass('timepicker-hour').attr('data-time-component', 'hours').attr('data-action', 'showHours')));
+                    bottomRow.append($('<td>')
+                        .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementHours')
+                            .append($('<span>').addClass(options.icons.down))));
+                }
+                if (isEnabled('m')) {
                     if (isEnabled('h')) {
-                        topRow.append($('<td>')
-                            .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementHours')
-                                .append($('<span>').addClass(options.icons.up))));
-                        middleRow.append($('<td>')
-                            .append($('<span>').addClass('timepicker-hour').attr('data-time-component', 'hours').attr('data-action', 'showHours')));
-                        bottomRow.append($('<td>')
-                            .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementHours')
-                                .append($('<span>').addClass(options.icons.down))));
-                    }
-                    if (isEnabled('m')) {
-                        if (isEnabled('h')) {
-                            topRow.append($('<td>').addClass('separator'));
-                            middleRow.append($('<td>').addClass('separator').html(':'));
-                            bottomRow.append($('<td>').addClass('separator'));
-                        }
-                        topRow.append($('<td>')
-                            .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementMinutes')
-                                .append($('<span>').addClass(options.icons.up))));
-                        middleRow.append($('<td>')
-                            .append($('<span>').addClass('timepicker-minute').attr('data-time-component', 'minutes').attr('data-action', 'showMinutes')));
-                        bottomRow.append($('<td>')
-                            .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementMinutes')
-                                .append($('<span>').addClass(options.icons.down))));
-                    }
-                    if (isEnabled('s')) {
-                        if (isEnabled('m')) {
-                            topRow.append($('<td>').addClass('separator'));
-                            middleRow.append($('<td>').addClass('separator').html(':'));
-                            bottomRow.append($('<td>').addClass('separator'));
-                        }
-                        topRow.append($('<td>')
-                            .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementSeconds')
-                                .append($('<span>').addClass(options.icons.up))));
-                        middleRow.append($('<td>')
-                            .append($('<span>').addClass('timepicker-second').attr('data-time-component', 'seconds').attr('data-action', 'showSeconds')));
-                        bottomRow.append($('<td>')
-                            .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementSeconds')
-                                .append($('<span>').addClass(options.icons.down))));
-                    }
-
-                    if (!use24hours) {
                         topRow.append($('<td>').addClass('separator'));
-                        middleRow.append($('<td>')
-                            .append($('<button>').addClass('btn btn-primary').attr('data-action', 'togglePeriod')));
+                        middleRow.append($('<td>').addClass('separator').html(':'));
                         bottomRow.append($('<td>').addClass('separator'));
                     }
-
-                    return $('<div>').addClass('timepicker-picker')
-                        .append($('<table>').addClass('table-condensed')
-                            .append([topRow, middleRow, bottomRow]));
-                },
-
-                getTimePickerTemplate = function () {
-                    var hoursView = $('<div>').addClass('timepicker-hours')
-                            .append($('<table>').addClass('table-condensed')),
-                        minutesView = $('<div>').addClass('timepicker-minutes')
-                            .append($('<table>').addClass('table-condensed')),
-                        secondsView = $('<div>').addClass('timepicker-seconds')
-                            .append($('<table>').addClass('table-condensed')),
-                        ret = [getTimePickerMainTemplate()];
-
-                    if (isEnabled('h')) {
-                        ret.push(hoursView);
-                    }
+                    topRow.append($('<td>')
+                        .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementMinutes')
+                            .append($('<span>').addClass(options.icons.up))));
+                    middleRow.append($('<td>')
+                        .append($('<span>').addClass('timepicker-minute').attr('data-time-component', 'minutes').attr('data-action', 'showMinutes')));
+                    bottomRow.append($('<td>')
+                        .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementMinutes')
+                            .append($('<span>').addClass(options.icons.down))));
+                }
+                if (isEnabled('s')) {
                     if (isEnabled('m')) {
-                        ret.push(minutesView);
-                    }
-                    if (isEnabled('s')) {
-                        ret.push(secondsView);
+                        topRow.append($('<td>').addClass('separator'));
+                        middleRow.append($('<td>').addClass('separator').html(':'));
+                        bottomRow.append($('<td>').addClass('separator'));
                     }
+                    topRow.append($('<td>')
+                        .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'incrementSeconds')
+                            .append($('<span>').addClass(options.icons.up))));
+                    middleRow.append($('<td>')
+                        .append($('<span>').addClass('timepicker-second').attr('data-time-component', 'seconds').attr('data-action', 'showSeconds')));
+                    bottomRow.append($('<td>')
+                        .append($('<a>').attr('href', '#').addClass('btn').attr('data-action', 'decrementSeconds')
+                            .append($('<span>').addClass(options.icons.down))));
+                }
 
-                    return ret;
-                },
+                if (!use24Hours) {
+                    topRow.append($('<td>').addClass('separator'));
+                    middleRow.append($('<td>')
+                        .append($('<button>').addClass('btn btn-primary').attr('data-action', 'togglePeriod')));
+                    bottomRow.append($('<td>').addClass('separator'));
+                }
 
-                getToolbar = function () {
-                    var row = [];
-                    if (options.showTodayButton) {
-                        row.push($('<td>').append($('<a>').attr('data-action', 'today').append($('<span>').addClass(options.icons.today))));
-                    }
-                    if (hasDate() && hasTime()) {
-                        row.push($('<td>').append($('<a>').attr('data-action', 'togglePicker').append($('<span>').addClass(options.icons.time))));
-                    }
-                    if (options.showClear) {
-                        row.push($('<td>').append($('<a>').attr('data-action', 'clear').append($('<span>').addClass(options.icons.clear))));
-                    }
-                    return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row)));
-                },
+                return $('<div>').addClass('timepicker-picker')
+                    .append($('<table>').addClass('table-condensed')
+                        .append([topRow, middleRow, bottomRow]));
+            },
 
-                getTemplate = function () {
-                    var template = $('<div>').addClass('bootstrap-datetimepicker-widget dropdown-menu'),
-                        dateView = $('<div>').addClass('datepicker').append(getDatePickerTemplate()),
-                        timeView = $('<div>').addClass('timepicker').append(getTimePickerTemplate()),
-                        content = $('<ul>').addClass('list-unstyled');
+            getTimePickerTemplate = function () {
+                var hoursView = $('<div>').addClass('timepicker-hours')
+                        .append($('<table>').addClass('table-condensed')),
+                    minutesView = $('<div>').addClass('timepicker-minutes')
+                        .append($('<table>').addClass('table-condensed')),
+                    secondsView = $('<div>').addClass('timepicker-seconds')
+                        .append($('<table>').addClass('table-condensed')),
+                    ret = [getTimePickerMainTemplate()];
 
-                    if (options.sideBySide && hasDate() && hasTime()) {
-                        template.addClass('timepicker-sbs');
-                        if (use24hours) {
-                            template.addClass('usetwentyfour');
-                        }
-                        template.append(
-                            $('<div>').addClass('row')
-                                .append(dateView.addClass('col-sm-6'))
-                                .append(timeView.addClass('col-sm-6'))
-                        );
-                        return template;
-                    }
+                if (isEnabled('h')) {
+                    ret.push(hoursView);
+                }
+                if (isEnabled('m')) {
+                    ret.push(minutesView);
+                }
+                if (isEnabled('s')) {
+                    ret.push(secondsView);
+                }
 
-                    if (hasDate()) {
-                        content.append($('<li>').addClass((options.collapse && hasTime() ? 'collapse in' : '')).append(dateView));
-                    }
-                    content.append($('<li>').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar()));
-                    if (hasTime()) {
-                        content.append($('<li>').addClass((options.collapse && hasDate() ? 'collapse' : '')).append(timeView));
-                    }
-                    return template.append(content);
-                },
+                return ret;
+            },
 
-                dataToOptions = function () {
-                    var eData = element.data(),
-                        dataOptions = {};
+            getToolbar = function () {
+                var row = [];
+                if (options.showTodayButton) {
+                    row.push($('<td>').append($('<a>').attr('data-action', 'today').append($('<span>').addClass(options.icons.today))));
+                }
+                if (!options.sideBySide && hasDate() && hasTime()) {
+                    row.push($('<td>').append($('<a>').attr('data-action', 'togglePicker').append($('<span>').addClass(options.icons.time))));
+                }
+                if (options.showClear) {
+                    row.push($('<td>').append($('<a>').attr('data-action', 'clear').append($('<span>').addClass(options.icons.clear))));
+                }
+                return $('<table>').addClass('table-condensed').append($('<tbody>').append($('<tr>').append(row)));
+            },
 
-                    if (eData.dateOptions && eData.dateOptions instanceof Object) {
-                        dataOptions = $.extend(true, dataOptions, eData.dateOptions);
-                    }
+            getTemplate = function () {
+                var template = $('<div>').addClass('bootstrap-datetimepicker-widget dropdown-menu'),
+                    dateView = $('<div>').addClass('datepicker').append(getDatePickerTemplate()),
+                    timeView = $('<div>').addClass('timepicker').append(getTimePickerTemplate()),
+                    content = $('<ul>').addClass('list-unstyled'),
+                    toolbar = $('<li>').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar());
 
-                    $.each(options, function (key) {
-                        var attributeName = 'date' + key.charAt(0).toUpperCase() + key.slice(1);
-                        if (eData[attributeName] !== undefined) {
-                            dataOptions[key] = eData[attributeName];
-                        }
-                    });
-                    return dataOptions;
-                },
+                if (use24Hours) {
+                    template.addClass('usetwentyfour');
+                }
+                if (options.sideBySide && hasDate() && hasTime()) {
+                    template.addClass('timepicker-sbs');
+                    template.append(
+                        $('<div>').addClass('row')
+                            .append(dateView.addClass('col-sm-6'))
+                            .append(timeView.addClass('col-sm-6'))
+                    );
+                    template.append(toolbar);
+                    return template;
+                }
 
-                place = function () {
-                    var offset = (component || element).position(),
-                        parent = element.is('input') ? element.parent() : element,
-                        vertical = options.widgetPositioning.vertical,
-                        horizontal = options.widgetPositioning.horizontal;
+                if (options.toolbarPlacement === 'top') {
+                    content.append(toolbar);
+                }
+                if (hasDate()) {
+                    content.append($('<li>').addClass((options.collapse && hasTime() ? 'collapse in' : '')).append(dateView));
+                }
+                if (options.toolbarPlacement === 'default') {
+                    content.append(toolbar);
+                }
+                if (hasTime()) {
+                    content.append($('<li>').addClass((options.collapse && hasDate() ? 'collapse' : '')).append(timeView));
+                }
+                if (options.toolbarPlacement === 'bottom') {
+                    content.append(toolbar);
+                }
+                return template.append(content);
+            },
 
-                    if (element.is('input')) {
-                        parent.append(widget);
-                    } else {
-                        element.children().first().after(widget);
-                    }
+            dataToOptions = function () {
+                var eData = element.data(),
+                    dataOptions = {};
 
-                    // Top and bottom logic
-                    if (vertical === 'auto') {
-                        if ((component || element).offset().top + widget.height() > $(window).height() + $(window).scrollTop() &&
-                                widget.height() + element.outerHeight() < (component || element).offset().top) {
-                            vertical = 'top';
-                        } else {
-                            vertical = 'bottom';
-                        }
-                    }
+                if (eData.dateOptions && eData.dateOptions instanceof Object) {
+                    dataOptions = $.extend(true, dataOptions, eData.dateOptions);
+                }
 
-                    // Left and right logic
-                    if (horizontal === 'auto') {
-                        if (parent.width() < offset.left + widget.outerWidth()) {
-                            horizontal = 'right';
-                        } else {
-                            horizontal = 'left';
-                        }
+                $.each(options, function (key) {
+                    var attributeName = 'date' + key.charAt(0).toUpperCase() + key.slice(1);
+                    if (eData[attributeName] !== undefined) {
+                        dataOptions[key] = eData[attributeName];
                     }
+                });
+                return dataOptions;
+            },
+
+            place = function () {
+                var offset = (component || element).position(),
+                    vertical = options.widgetPositioning.vertical,
+                    horizontal = options.widgetPositioning.horizontal,
+                    parent;
+
+                if (options.widgetParent) {
+                    parent = options.widgetParent.append(widget);
+                } else if (element.is('input')) {
+                    parent = element.parent().append(widget);
+                } else {
+                    parent = element;
+                    element.children().first().after(widget);
+                }
 
-                    if (vertical === 'top') {
-                        widget.addClass('top').removeClass('bottom');
+                // Top and bottom logic
+                if (vertical === 'auto') {
+                    if ((component || element).offset().top + widget.height() > $(window).height() + $(window).scrollTop() &&
+                            widget.height() + element.outerHeight() < (component || element).offset().top) {
+                        vertical = 'top';
                     } else {
-                        widget.addClass('bottom').removeClass('top');
+                        vertical = 'bottom';
                     }
+                }
 
-                    if (horizontal === 'right') {
-                        widget.addClass('pull-right');
+                // Left and right logic
+                if (horizontal === 'auto') {
+                    if (parent.width() < offset.left + widget.outerWidth()) {
+                        horizontal = 'right';
                     } else {
-                        widget.removeClass('pull-right');
+                        horizontal = 'left';
                     }
+                }
 
-                    // find the first parent element that has a relative css positioning
-                    if (parent.css('position') !== 'relative') {
-                        parent = parent.parents().filter(function () {
-                            return $(this).css('position') === 'relative';
-                        }).first();
-                    }
+                if (vertical === 'top') {
+                    widget.addClass('top').removeClass('bottom');
+                } else {
+                    widget.addClass('bottom').removeClass('top');
+                }
 
-                    if (parent.length === 0) {
-                        throw new Error('datetimepicker component should be placed within a relative positioned container');
-                    }
+                if (horizontal === 'right') {
+                    widget.addClass('pull-right');
+                } else {
+                    widget.removeClass('pull-right');
+                }
 
-                    widget.css({
-                        top: vertical === 'top' ? 'auto' : offset.top + element.outerHeight(),
-                        bottom: vertical === 'top' ? offset.top + element.outerHeight() : 'auto',
-                        left: horizontal === 'left' ? parent.css('padding-left') : 'auto',
-                        right: horizontal === 'left' ? 'auto' : parent.css('padding-right')
-                    });
-                },
+                // find the first parent element that has a relative css positioning
+                if (parent.css('position') !== 'relative') {
+                    parent = parent.parents().filter(function () {
+                        return $(this).css('position') === 'relative';
+                    }).first();
+                }
 
-                notifyEvent = function (e) {
-                    if (e.type === 'change.dp' && e.date && e.date.isSame(e.oldDate) && !errored && !unset) {
-                        return;
-                    }
-                    element.trigger(e);
-                },
+                if (parent.length === 0) {
+                    throw new Error('datetimepicker component should be placed within a relative positioned container');
+                }
 
-                showMode = function (dir) {
-                    if (!widget) {
-                        return;
-                    }
-                    if (dir) {
-                        currentViewMode = Math.max(minViewModeNumber, Math.min(2, currentViewMode + dir));
-                    }
-                    widget.find('.datepicker > div').hide().filter('.datepicker-' + datePickerModes[currentViewMode].clsName).show();
-                },
+                widget.css({
+                    top: vertical === 'top' ? 'auto' : offset.top + element.outerHeight(),
+                    bottom: vertical === 'top' ? offset.top + element.outerHeight() : 'auto',
+                    left: horizontal === 'left' ? parent.css('padding-left') : 'auto',
+                    right: horizontal === 'left' ? 'auto' : parent.css('padding-right')
+                });
+            },
 
-                fillDow = function () {
-                    var row = $('<tr>'),
-                        currentDate = viewDate.clone().startOf('w');
+            notifyEvent = function (e) {
+                if (e.type === 'dp.change' && ((e.date && e.date.isSame(e.oldDate)) || (!e.date && !e.oldDate))) {
+                    return;
+                }
+                element.trigger(e);
+            },
 
-                    if (options.calendarWeeks === true) {
-                        row.append($('<th>').addClass('cw').text('#'));
-                    }
+            showMode = function (dir) {
+                if (!widget) {
+                    return;
+                }
+                if (dir) {
+                    currentViewMode = Math.max(minViewModeNumber, Math.min(2, currentViewMode + dir));
+                }
+                widget.find('.datepicker > div').hide().filter('.datepicker-' + datePickerModes[currentViewMode].clsName).show();
+            },
 
-                    while (currentDate.isBefore(viewDate.clone().endOf('w'))) {
-                        row.append($('<th>').addClass('dow').text(currentDate.format('dd')));
-                        currentDate.add(1, 'd');
-                    }
-                    widget.find('.datepicker-days thead').append(row);
-                },
+            fillDow = function () {
+                var row = $('<tr>'),
+                    currentDate = viewDate.clone().startOf('w');
 
-                isInDisabledDates = function (date) {
-                    if (!options.disabledDates) {
-                        return false;
-                    }
-                    return options.disabledDates[date.format('YYYY-MM-DD')] === true;
-                },
+                if (options.calendarWeeks === true) {
+                    row.append($('<th>').addClass('cw').text('#'));
+                }
 
-                isInEnabledDates = function (date) {
-                    if (!options.enabledDates) {
-                        return false;
-                    }
-                    return options.enabledDates[date.format('YYYY-MM-DD')] === true;
-                },
+                while (currentDate.isBefore(viewDate.clone().endOf('w'))) {
+                    row.append($('<th>').addClass('dow').text(currentDate.format('dd')));
+                    currentDate.add(1, 'd');
+                }
+                widget.find('.datepicker-days thead').append(row);
+            },
 
-                isValid = function (targetMoment, granularity) {
-                    if (!targetMoment.isValid()) {
-                        return false;
-                    }
-                    if (options.disabledDates && isInDisabledDates(targetMoment)) {
-                        return false;
-                    }
-                    if (options.enabledDates && isInEnabledDates(targetMoment)) {
-                        return true;
-                    }
-                    if (options.minDate && targetMoment.isBefore(options.minDate, granularity)) {
-                        return false;
-                    }
-                    if (options.maxDate && targetMoment.isAfter(options.maxDate, granularity)) {
-                        return false;
-                    }
-                    if (options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) {
-                        return false;
-                    }
+            isInDisabledDates = function (date) {
+                if (!options.disabledDates) {
+                    return false;
+                }
+                return options.disabledDates[date.format('YYYY-MM-DD')] === true;
+            },
+
+            isInEnabledDates = function (date) {
+                if (!options.enabledDates) {
+                    return false;
+                }
+                return options.enabledDates[date.format('YYYY-MM-DD')] === true;
+            },
+
+            isValid = function (targetMoment, granularity) {
+                if (!targetMoment.isValid()) {
+                    return false;
+                }
+                if (options.disabledDates && isInDisabledDates(targetMoment)) {
+                    return false;
+                }
+                if (options.enabledDates && isInEnabledDates(targetMoment)) {
                     return true;
-                },
+                }
+                if (options.minDate && targetMoment.isBefore(options.minDate, granularity)) {
+                    return false;
+                }
+                if (options.maxDate && targetMoment.isAfter(options.maxDate, granularity)) {
+                    return false;
+                }
+                if (granularity === 'd' && options.daysOfWeekDisabled.indexOf(targetMoment.day()) !== -1) {
+                    return false;
+                }
+                return true;
+            },
 
-                fillMonths = function () {
-                    var spans = [],
-                        monthsShort = viewDate.clone().startOf('y').hour(12); // hour is changed to avoid DST issues in some browsers
-                    while (monthsShort.isSame(viewDate, 'y')) {
-                        spans.push($('<span>').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM')));
-                        monthsShort.add(1, 'M');
-                    }
-                    widget.find('.datepicker-months td').empty().append(spans);
-                },
+            fillMonths = function () {
+                var spans = [],
+                    monthsShort = viewDate.clone().startOf('y').hour(12); // hour is changed to avoid DST issues in some browsers
+                while (monthsShort.isSame(viewDate, 'y')) {
+                    spans.push($('<span>').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM')));
+                    monthsShort.add(1, 'M');
+                }
+                widget.find('.datepicker-months td').empty().append(spans);
+            },
 
-                updateMonths = function () {
-                    var monthsView = widget.find('.datepicker-months'),
-                        monthsViewHeader = monthsView.find('th'),
-                        months = monthsView.find('tbody').find('span');
+            updateMonths = function () {
+                var monthsView = widget.find('.datepicker-months'),
+                    monthsViewHeader = monthsView.find('th'),
+                    months = monthsView.find('tbody').find('span');
 
-                    monthsView.find('.disabled').removeClass('disabled');
+                monthsView.find('.disabled').removeClass('disabled');
 
-                    if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) {
-                        monthsViewHeader.eq(0).addClass('disabled');
-                    }
+                if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) {
+                    monthsViewHeader.eq(0).addClass('disabled');
+                }
 
-                    monthsViewHeader.eq(1).text(viewDate.year());
+                monthsViewHeader.eq(1).text(viewDate.year());
 
-                    if (!isValid(viewDate.clone().add(1, 'y'), 'y')) {
-                        monthsViewHeader.eq(2).addClass('disabled');
-                    }
+                if (!isValid(viewDate.clone().add(1, 'y'), 'y')) {
+                    monthsViewHeader.eq(2).addClass('disabled');
+                }
 
-                    months.removeClass('active');
-                    if (date.isSame(viewDate, 'y')) {
-                        months.eq(date.month()).addClass('active');
+                months.removeClass('active');
+                if (date.isSame(viewDate, 'y')) {
+                    months.eq(date.month()).addClass('active');
+                }
+
+                months.each(function (index) {
+                    if (!isValid(viewDate.clone().month(index), 'M')) {
+                        $(this).addClass('disabled');
                     }
+                });
+            },
 
-                    months.each(function (index) {
-                        if (!isValid(viewDate.clone().month(index), 'M')) {
-                            $(this).addClass('disabled');
-                        }
-                    });
-                },
+            updateYears = function () {
+                var yearsView = widget.find('.datepicker-years'),
+                    yearsViewHeader = yearsView.find('th'),
+                    startYear = viewDate.clone().subtract(5, 'y'),
+                    endYear = viewDate.clone().add(6, 'y'),
+                    html = '';
 
-                updateYears = function () {
-                    var yearsView = widget.find('.datepicker-years'),
-                        yearsViewHeader = yearsView.find('th'),
-                        startYear = viewDate.clone().subtract(5, 'y'),
-                        endYear = viewDate.clone().add(6, 'y'),
-                        html = '';
+                yearsView.find('.disabled').removeClass('disabled');
 
-                    yearsView.find('.disabled').removeClass('disabled');
+                if (options.minDate && options.minDate.isAfter(startYear, 'y')) {
+                    yearsViewHeader.eq(0).addClass('disabled');
+                }
 
-                    if (options.minDate && options.minDate.isAfter(startYear, 'y')) {
-                        yearsViewHeader.eq(0).addClass('disabled');
-                    }
+                yearsViewHeader.eq(1).text(startYear.year() + '-' + endYear.year());
 
-                    yearsViewHeader.eq(1).text(startYear.year() + '-' + endYear.year());
+                if (options.maxDate && options.maxDate.isBefore(endYear, 'y')) {
+                    yearsViewHeader.eq(2).addClass('disabled');
+                }
 
-                    if (options.maxDate && options.maxDate.isBefore(endYear, 'y')) {
-                        yearsViewHeader.eq(2).addClass('disabled');
-                    }
+                while (!startYear.isAfter(endYear, 'y')) {
+                    html += '<span data-action="selectYear" class="year' + (startYear.isSame(date, 'y') ? ' active' : '') + (!isValid(startYear, 'y') ? ' disabled' : '') + '">' + startYear.year() + '</span>';
+                    startYear.add(1, 'y');
+                }
 
-                    while (!startYear.isAfter(endYear, 'y')) {
-                        html += '<span data-action="selectYear" class="year' + (startYear.isSame(date, 'y') ? ' active' : '') + (!isValid(startYear, 'y') ? ' disabled' : '') + '">' + startYear.year() + '</span>';
-                        startYear.add(1, 'y');
-                    }
+                yearsView.find('td').html(html);
+            },
 
-                    yearsView.find('td').html(html);
-                },
+            fillDate = function () {
+                var daysView = widget.find('.datepicker-days'),
+                    daysViewHeader = daysView.find('th'),
+                    currentDate,
+                    html = [],
+                    row,
+                    clsName;
 
-                fillDate = function () {
-                    var daysView = widget.find('.datepicker-days'),
-                        daysViewHeader = daysView.find('th'),
-                        currentDate,
-                        html = [],
-                        row,
-                        clsName;
+                if (!hasDate()) {
+                    return;
+                }
 
-                    if (!hasDate()) {
-                        return;
-                    }
+                daysView.find('.disabled').removeClass('disabled');
+                daysViewHeader.eq(1).text(viewDate.format(options.dayViewHeaderFormat));
 
-                    daysView.find('.disabled').removeClass('disabled');
+                if (!isValid(viewDate.clone().subtract(1, 'M'), 'M')) {
+                    daysViewHeader.eq(0).addClass('disabled');
+                }
+                if (!isValid(viewDate.clone().add(1, 'M'), 'M')) {
+                    daysViewHeader.eq(2).addClass('disabled');
+                }
 
-                    daysViewHeader.eq(1).text(viewDate.format('MMMM YYYY'));
+                currentDate = viewDate.clone().startOf('M').startOf('week');
 
-                    if (!isValid(viewDate.clone().subtract(1, 'M'), 'M')) {
-                        daysViewHeader.eq(0).addClass('disabled');
+                while (!viewDate.clone().endOf('M').endOf('w').isBefore(currentDate, 'd')) {
+                    if (currentDate.weekday() === 0) {
+                        row = $('<tr>');
+                        if (options.calendarWeeks) {
+                            row.append('<td class="cw">' + currentDate.week() + '</td>');
+                        }
+                        html.push(row);
                     }
-                    if (!isValid(viewDate.clone().add(1, 'M'), 'M')) {
-                        daysViewHeader.eq(2).addClass('disabled');
+                    clsName = '';
+                    if (currentDate.isBefore(viewDate, 'M')) {
+                        clsName += ' old';
                     }
-
-                    currentDate = viewDate.clone().startOf('M').startOf('week');
-
-                    while (!viewDate.clone().endOf('M').endOf('w').isBefore(currentDate, 'd')) {
-                        if (currentDate.weekday() === 0) {
-                            row = $('<tr>');
-                            if (options.calendarWeeks) {
-                                row.append('<td class="cw">' + currentDate.week() + '</td>');
-                            }
-                            html.push(row);
-                        }
-                        clsName = '';
-                        if (currentDate.isBefore(viewDate, 'M')) {
-                            clsName += ' old';
-                        }
-                        if (currentDate.isAfter(viewDate, 'M')) {
-                            clsName += ' new';
-                        }
-                        if (currentDate.isSame(date, 'd') && !unset) {
-                            clsName += ' active';
-                        }
-                        if (!isValid(currentDate, 'd')) {
-                            clsName += ' disabled';
-                        }
-                        if (currentDate.isSame(moment(), 'd')) {
-                            clsName += ' today';
-                        }
-                        row.append('<td data-action="selectDay" class="day' + clsName + '">' + currentDate.date() + '</td>');
-                        currentDate.add(1, 'd');
+                    if (currentDate.isAfter(viewDate, 'M')) {
+                        clsName += ' new';
                     }
+                    if (currentDate.isSame(date, 'd') && !unset) {
+                        clsName += ' active';
+                    }
+                    if (!isValid(currentDate, 'd')) {
+                        clsName += ' disabled';
+                    }
+                    if (currentDate.isSame(moment(), 'd')) {
+                        clsName += ' today';
+                    }
+                    if (currentDate.day() === 0 || currentDate.day() === 6) {
+                        clsName += ' weekend';
+                    }
+                    row.append('<td data-action="selectDay" class="day' + clsName + '">' + currentDate.date() + '</td>');
+                    currentDate.add(1, 'd');
+                }
 
-                    daysView.find('tbody').empty().append(html);
+                daysView.find('tbody').empty().append(html);
 
-                    updateMonths();
+                updateMonths();
 
-                    updateYears();
-                },
+                updateYears();
+            },
 
-                fillHours = function () {
-                    var table = widget.find('.timepicker-hours table'),
-                        currentHour = viewDate.clone().startOf('d'),
-                        html = [],
-                        row;
+            fillHours = function () {
+                var table = widget.find('.timepicker-hours table'),
+                    currentHour = viewDate.clone().startOf('d'),
+                    html = [],
+                    row = $('<tr>');
 
-                    if (viewDate.hour() > 11 && !use24hours) {
-                        currentHour.hour(12);
-                    }
-                    while (currentHour.isSame(viewDate, 'd') && (use24hours || (viewDate.hour() < 12 && currentHour.hour() < 12) || viewDate.hour() > 11)) {
-                        if (currentHour.hour() % 4 === 0) {
-                            row = $('<tr>');
-                            html.push(row);
-                        }
-                        row.append('<td data-action="selectHour" class="hour' + (!isValid(currentHour, 'h') ? ' disabled' : '') + '">' + currentHour.format(use24hours ? 'HH' : 'hh') + '</td>');
-                        currentHour.add(1, 'h');
+                if (viewDate.hour() > 11 && !use24Hours) {
+                    currentHour.hour(12);
+                }
+                while (currentHour.isSame(viewDate, 'd') && (use24Hours || (viewDate.hour() < 12 && currentHour.hour() < 12) || viewDate.hour() > 11)) {
+                    if (currentHour.hour() % 4 === 0) {
+                        row = $('<tr>');
+                        html.push(row);
                     }
-                    table.empty().append(html);
-                },
+                    row.append('<td data-action="selectHour" class="hour' + (!isValid(currentHour, 'h') ? ' disabled' : '') + '">' + currentHour.format(use24Hours ? 'HH' : 'hh') + '</td>');
+                    currentHour.add(1, 'h');
+                }
+                table.empty().append(html);
+            },
 
-                fillMinutes = function () {
-                    var table = widget.find('.timepicker-minutes table'),
-                        currentMinute = viewDate.clone().startOf('h'),
-                        html = [],
-                        row,
-                        step = options.stepping === 1 ? 5 : options.stepping;
-
-                    while (viewDate.isSame(currentMinute, 'h')) {
-                        if (currentMinute.minute() % (step * 4) === 0) {
-                            row = $('<tr>');
-                            html.push(row);
-                        }
-                        row.append('<td data-action="selectMinute" class="minute' + (!isValid(currentMinute, 'm') ? ' disabled' : '') + '">' + currentMinute.format('mm') + '</td>');
-                        currentMinute.add(step, 'm');
+            fillMinutes = function () {
+                var table = widget.find('.timepicker-minutes table'),
+                    currentMinute = viewDate.clone().startOf('h'),
+                    html = [],
+                    row = $('<tr>'),
+                    step = options.stepping === 1 ? 5 : options.stepping;
+
+                while (viewDate.isSame(currentMinute, 'h')) {
+                    if (currentMinute.minute() % (step * 4) === 0) {
+                        row = $('<tr>');
+                        html.push(row);
                     }
-                    table.empty().append(html);
-                },
+                    row.append('<td data-action="selectMinute" class="minute' + (!isValid(currentMinute, 'm') ? ' disabled' : '') + '">' + currentMinute.format('mm') + '</td>');
+                    currentMinute.add(step, 'm');
+                }
+                table.empty().append(html);
+            },
 
-                fillSeconds = function () {
-                    var table = widget.find('.timepicker-seconds table'),
-                        currentSecond = viewDate.clone().startOf('m'),
-                        html = [],
-                        row;
+            fillSeconds = function () {
+                var table = widget.find('.timepicker-seconds table'),
+                    currentSecond = viewDate.clone().startOf('m'),
+                    html = [],
+                    row = $('<tr>');
 
-                    while (viewDate.isSame(currentSecond, 'm')) {
-                        if (currentSecond.second() % 20 === 0) {
-                            row = $('<tr>');
-                            html.push(row);
-                        }
-                        row.append('<td data-action="selectSecond" class="second' + (!isValid(currentSecond, 's') ? ' disabled' : '') + '">' + currentSecond.format('ss') + '</td>');
-                        currentSecond.add(5, 's');
+                while (viewDate.isSame(currentSecond, 'm')) {
+                    if (currentSecond.second() % 20 === 0) {
+                        row = $('<tr>');
+                        html.push(row);
                     }
+                    row.append('<td data-action="selectSecond" class="second' + (!isValid(currentSecond, 's') ? ' disabled' : '') + '">' + currentSecond.format('ss') + '</td>');
+                    currentSecond.add(5, 's');
+                }
 
-                    table.empty().append(html);
-                },
+                table.empty().append(html);
+            },
 
-                fillTime = function () {
-                    var timeComponents = widget.find('.timepicker span[data-time-component]');
-                    if (!use24hours) {
-                        widget.find('.timepicker [data-action=togglePeriod]').text(date.format('A'));
-                    }
-                    timeComponents.filter('[data-time-component=hours]').text(date.format(use24hours ? 'HH' : 'hh'));
-                    timeComponents.filter('[data-time-component=minutes]').text(date.format('mm'));
-                    timeComponents.filter('[data-time-component=seconds]').text(date.format('ss'));
+            fillTime = function () {
+                var timeComponents = widget.find('.timepicker span[data-time-component]');
+                if (!use24Hours) {
+                    widget.find('.timepicker [data-action=togglePeriod]').text(date.format('A'));
+                }
+                timeComponents.filter('[data-time-component=hours]').text(date.format(use24Hours ? 'HH' : 'hh'));
+                timeComponents.filter('[data-time-component=minutes]').text(date.format('mm'));
+                timeComponents.filter('[data-time-component=seconds]').text(date.format('ss'));
 
-                    fillHours();
-                    fillMinutes();
-                    fillSeconds();
-                },
+                fillHours();
+                fillMinutes();
+                fillSeconds();
+            },
+
+            update = function () {
+                if (!widget) {
+                    return;
+                }
+                fillDate();
+                fillTime();
+            },
+
+            setValue = function (targetMoment) {
+                var oldDate = unset ? null : date;
+
+                // case of calling setValue(null or false)
+                if (!targetMoment) {
+                    unset = true;
+                    input.val('');
+                    element.data('date', '');
+                    notifyEvent({
+                        type: 'dp.change',
+                        date: null,
+                        oldDate: oldDate
+                    });
+                    update();
+                    return;
+                }
+
+                targetMoment = targetMoment.clone().locale(options.locale);
 
-                update = function () {
-                    if (!widget) {
-                        return;
+                if (options.stepping !== 1) {
+                    targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping) % 60).seconds(0);
+                }
+
+                if (isValid(targetMoment)) {
+                    date = targetMoment;
+                    viewDate = date.clone();
+                    input.val(date.format(actualFormat));
+                    element.data('date', date.format(actualFormat));
+                    update();
+                    unset = false;
+                    notifyEvent({
+                        type: 'dp.change',
+                        date: date.clone(),
+                        oldDate: oldDate
+                    });
+                } else {
+                    input.val(unset ? '' : date.format(actualFormat));
+                    notifyEvent({
+                        type: 'dp.error',
+                        date: targetMoment
+                    });
+                }
+            },
+
+            hide = function () {
+                var transitioning = false;
+                if (!widget) {
+                    return picker;
+                }
+                // Ignore event if in the middle of a picker transition
+                widget.find('.collapse').each(function () {
+                    var collapseData = $(this).data('collapse');
+                    if (collapseData && collapseData.transitioning) {
+                        transitioning = true;
+                        return false;
                     }
+                });
+                if (transitioning) {
+                    return picker;
+                }
+                if (component && component.hasClass('btn')) {
+                    component.toggleClass('active');
+                }
+                widget.hide();
+
+                $(window).off('resize', place);
+                widget.off('click', '[data-action]');
+                widget.off('mousedown', false);
+
+                widget.remove();
+                widget = false;
+
+                notifyEvent({
+                    type: 'dp.hide',
+                    date: date.clone()
+                });
+                return picker;
+            },
+
+            /********************************************************************************
+             *
+             * Widget UI interaction functions
+             *
+             ********************************************************************************/
+            actions = {
+                next: function () {
+                    viewDate.add(datePickerModes[currentViewMode].navStep, datePickerModes[currentViewMode].navFnc);
                     fillDate();
-                    fillTime();
                 },
 
-                setValue = function (targetMoment) {
-                    var oldDate = date;
-
-                    // case of calling setValue(null or false)
-                    if (!targetMoment) {
-                        unset = true;
-                        input.val('');
-                        element.data('date', '');
-                        notifyEvent({
-                            type: 'change.dp',
-                            date: null,
-                            oldDate: oldDate
-                        });
-                        update();
-                        return;
-                    }
+                previous: function () {
+                    viewDate.subtract(datePickerModes[currentViewMode].navStep, datePickerModes[currentViewMode].navFnc);
+                    fillDate();
+                },
 
-                    targetMoment = targetMoment.clone().locale(options.locale);
+                pickerSwitch: function () {
+                    showMode(1);
+                },
 
-                    if (options.stepping !== 1) {
-                        targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping) % 60).seconds(0);
+                selectMonth: function (e) {
+                    var month = $(e.target).closest('tbody').find('span').index($(e.target));
+                    viewDate.month(month);
+                    if (currentViewMode === minViewModeNumber) {
+                        setValue(date.clone().year(viewDate.year()).month(viewDate.month()));
+                        hide();
                     }
+                    showMode(-1);
+                    fillDate();
+                },
 
-                    if (isValid(targetMoment)) {
-                        date = targetMoment;
-                        viewDate = date.clone();
-                        input.val(date.format(actualFormat));
-                        element.data('date', date.format(actualFormat));
-                        update();
-                        notifyEvent({
-                            type: 'change.dp',
-                            date: date.clone(),
-                            oldDate: oldDate
-                        });
-                        errored = false;
-                        unset = false;
-                    } else {
-                        errored = true;
-                        unset = true;
-                        notifyEvent({
-                            type: 'error.dp',
-                            date: targetMoment
-                        });
+                selectYear: function (e) {
+                    var year = parseInt($(e.target).text(), 10) || 0;
+                    viewDate.year(year);
+                    if (currentViewMode === minViewModeNumber) {
+                        setValue(date.clone().year(viewDate.year()));
+                        hide();
                     }
+                    showMode(-1);
+                    fillDate();
                 },
 
-                hide = function () {
-                    var transitioning = false;
-                    if (!widget) {
-                        return picker;
-                    }
-                    // Ignore event if in the middle of a picker transition
-                    widget.find('.collapse').each(function () {
-                        var collapseData = $(this).data('collapse');
-                        if (collapseData && collapseData.transitioning) {
-                            transitioning = true;
-                            return false;
-                        }
-                    });
-                    if (transitioning) {
-                        return picker;
+                selectDay: function (e) {
+                    var day = viewDate.clone();
+                    if ($(e.target).is('.old')) {
+                        day.subtract(1, 'M');
                     }
-                    if (component && component.hasClass('btn')) {
-                        component.toggleClass('active');
+                    if ($(e.target).is('.new')) {
+                        day.add(1, 'M');
                     }
-                    widget.hide();
-
-                    $(window).off('resize', place);
-                    widget.off('click', '[data-action]');
-                    widget.off('mousedown', false);
-                    if (!element.is('input')) {
-                        $(document).off('mousedown', hide);
+                    setValue(day.date(parseInt($(e.target).text(), 10)));
+                    if (!hasTime() && !options.keepOpen) {
+                        hide();
                     }
+                },
 
-                    widget.remove();
-                    widget = false;
-
-                    notifyEvent({
-                        type: 'hide.dp'
-                    });
-                    return picker;
+                incrementHours: function () {
+                    setValue(date.clone().add(1, 'h'));
                 },
 
-                /********************************************************************************
-                 *
-                 * Widget UI interaction functions
-                 *
-                 ********************************************************************************/
-                actions = {
-                    next: function () {
-                        viewDate.add(datePickerModes[currentViewMode].navStep, datePickerModes[currentViewMode].navFnc);
-                        fillDate();
-                    },
-
-                    previous: function () {
-                        viewDate.subtract(datePickerModes[currentViewMode].navStep, datePickerModes[currentViewMode].navFnc);
-                        fillDate();
-                    },
-
-                    pickerSwitch: function () {
-                        showMode(1);
-                    },
-
-                    selectMonth: function (e) {
-                        var month = $(e.target).closest('tbody').find('span').index($(e.target));
-                        viewDate.month(month);
-                        if (currentViewMode === minViewModeNumber) {
-                            setValue(date.clone().year(viewDate.year()).month(viewDate.month()));
-                            hide();
-                        }
-                        showMode(-1);
-                        fillDate();
-                    },
-
-                    selectYear: function (e) {
-                        var year = parseInt($(e.target).text(), 10) || 0;
-                        viewDate.year(year);
-                        if (currentViewMode === minViewModeNumber) {
-                            setValue(date.clone().year(viewDate.year()));
-                            hide();
-                        }
-                        showMode(-1);
-                        fillDate();
-                    },
-
-                    selectDay: function (e) {
-                        var day = viewDate.clone();
-                        if ($(e.target).is('.old')) {
-                            day.subtract(1, 'M');
-                        }
-                        if ($(e.target).is('.new')) {
-                            day.add(1, 'M');
-                        }
-                        setValue(day.date(parseInt($(e.target).text(), 10)));
-                        if (!hasTime()) {
-                            hide();
-                        }
-                    },
-
-                    incrementHours: function () {
-                        setValue(date.clone().add(1, 'h'));
-                    },
-
-                    incrementMinutes: function () {
-                        setValue(date.clone().add(options.stepping, 'm'));
-                    },
-
-                    incrementSeconds: function () {
-                        setValue(date.clone().add(1, 's'));
-                    },
-
-                    decrementHours: function () {
-                        setValue(date.clone().subtract(1, 'h'));
-                    },
-
-                    decrementMinutes: function () {
-                        setValue(date.clone().subtract(options.stepping, 'm'));
-                    },
-
-                    decrementSeconds: function () {
-                        setValue(date.clone().subtract(1, 's'));
-                    },
-
-                    togglePeriod: function () {
-                        setValue(date.clone().add((date.hours() >= 12) ? -12 : 12, 'h'));
-                    },
-
-                    togglePicker: function (e) {
-                        var $this = $(e.target),
-                            $parent = $this.closest('ul'),
-                            expanded = $parent.find('.in'),
-                            closed = $parent.find('.collapse:not(.in)'),
-                            collapseData;
-
-                        if (expanded && expanded.length) {
-                            collapseData = expanded.data('collapse');
-                            if (collapseData && collapseData.transitioning) {
-                                return;
-                            }
-                            expanded.collapse('hide');
-                            closed.collapse('show');
-                            if ($this.is('span')) {
-                                $this.toggleClass(options.icons.time + ' ' + options.icons.date);
-                            } else {
-                                $this.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
-                            }
-                            if (component) {
-                                component.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
-                            }
-                        }
-                    },
-
-                    showPicker: function () {
-                        widget.find('.timepicker > div:not(.timepicker-picker)').hide();
-                        widget.find('.timepicker .timepicker-picker').show();
-                    },
-
-                    showHours: function () {
-                        widget.find('.timepicker .timepicker-picker').hide();
-                        widget.find('.timepicker .timepicker-hours').show();
-                    },
-
-                    showMinutes: function () {
-                        widget.find('.timepicker .timepicker-picker').hide();
-                        widget.find('.timepicker .timepicker-minutes').show();
-                    },
-
-                    showSeconds: function () {
-                        widget.find('.timepicker .timepicker-picker').hide();
-                        widget.find('.timepicker .timepicker-seconds').show();
-                    },
-
-                    selectHour: function (e) {
-                        var hour = parseInt($(e.target).text(), 10);
-
-                        if (!use24hours) {
-                            if (date.hours() >= 12) {
-                                if (hour !== 12) {
-                                    hour += 12;
-                                }
-                            } else {
-                                if (hour === 12) {
-                                    hour = 0;
-                                }
-                            }
-                        }
-                        setValue(date.clone().hours(hour));
-                        actions.showPicker.call(picker);
-                    },
-
-                    selectMinute: function (e) {
-                        setValue(date.clone().minutes(parseInt($(e.target).text(), 10)));
-                        actions.showPicker.call(picker);
-                    },
-
-                    selectSecond: function (e) {
-                        setValue(date.clone().seconds(parseInt($(e.target).text(), 10)));
-                        actions.showPicker.call(picker);
-                    },
-
-                    clear: function () {
-                        setValue(null);
-                    },
-
-                    today: function () {
-                        setValue(moment());
-                    }
+                incrementMinutes: function () {
+                    setValue(date.clone().add(options.stepping, 'm'));
                 },
 
-                doAction = function (e) {
-                    if ($(e.currentTarget).is('.disabled')) {
-                        return false;
-                    }
-                    actions[$(e.currentTarget).data('action')].apply(picker, arguments);
-                    return false;
+                incrementSeconds: function () {
+                    setValue(date.clone().add(1, 's'));
                 },
 
-                show = function () {
-                    var currentMoment,
-                        useCurrentGranularity = {
-                            'year': function (m) {
-                                return m.month(0).date(1).hours(0).seconds(0).minutes(0);
-                            },
-                            'month': function (m) {
-                                return m.date(1).hours(0).seconds(0).minutes(0);
-                            },
-                            'day': function (m) {
-                                return m.hours(0).seconds(0).minutes(0);
-                            },
-                            'hour': function (m) {
-                                return m.seconds(0).minutes(0);
-                            },
-                            'minute': function (m) {
-                                return m.seconds(0);
-                            }
-                        };
+                decrementHours: function () {
+                    setValue(date.clone().subtract(1, 'h'));
+                },
 
-                    if (input.prop('disabled') || input.prop('readonly') || widget) {
-                        return picker;
-                    }
-                    if (options.useCurrent && unset) {
-                        currentMoment = moment();
-                        if (typeof options.useCurrent === 'string') {
-                            currentMoment = useCurrentGranularity[options.useCurrent](currentMoment);
-                        }
-                        setValue(currentMoment);
-                    }
+                decrementMinutes: function () {
+                    setValue(date.clone().subtract(options.stepping, 'm'));
+                },
 
-                    widget = getTemplate();
+                decrementSeconds: function () {
+                    setValue(date.clone().subtract(1, 's'));
+                },
 
-                    fillDow();
-                    fillMonths();
+                togglePeriod: function () {
+                    setValue(date.clone().add((date.hours() >= 12) ? -12 : 12, 'h'));
+                },
 
-                    widget.find('.timepicker-hours').hide();
-                    widget.find('.timepicker-minutes').hide();
-                    widget.find('.timepicker-seconds').hide();
+                togglePicker: function (e) {
+                    var $this = $(e.target),
+                        $parent = $this.closest('ul'),
+                        expanded = $parent.find('.in'),
+                        closed = $parent.find('.collapse:not(.in)'),
+                        collapseData;
 
-                    update();
-                    showMode();
-                    $(window).on('resize', place);
-                    widget.on('click', '[data-action]', doAction); // this handles clicks on the widget
-                    widget.on('mousedown', false);
-                    if (!element.is('input')) {
-                        $(document).on('mousedown', hide);
-                    }
+                    if (expanded && expanded.length) {
+                        collapseData = expanded.data('collapse');
+                        if (collapseData && collapseData.transitioning) {
+                            return;
+                        }
+                        expanded.collapse('hide');
+                        closed.collapse('show');
+                        if ($this.is('span')) {
+                            $this.toggleClass(options.icons.time + ' ' + options.icons.date);
+                        } else {
+                            $this.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
+                        }
 
-                    if (component && component.hasClass('btn')) {
-                        component.toggleClass('active');
+                        // NOTE: uncomment if toggled state will be restored in show()
+                        //if (component) {
+                        //    component.find('span').toggleClass(options.icons.time + ' ' + options.icons.date);
+                        //}
                     }
-                    widget.show();
-                    place();
-                    notifyEvent({
-                        type: 'show.dp'
-                    });
-                    return picker;
                 },
 
-                toggle = function () {
-                    return (widget ? hide() : show());
+                showPicker: function () {
+                    widget.find('.timepicker > div:not(.timepicker-picker)').hide();
+                    widget.find('.timepicker .timepicker-picker').show();
                 },
 
-                parseInputDate = function (date) {
-                    if (moment.isMoment(date) || date instanceof Date) {
-                        date = moment(date);
-                    } else {
-                        date = moment(date, actualFormat, options.useStrict);
-                    }
-                    date.locale(options.locale);
-                    return date;
+                showHours: function () {
+                    widget.find('.timepicker .timepicker-picker').hide();
+                    widget.find('.timepicker .timepicker-hours').show();
                 },
 
-                keydown = function (e) {
-                    if (e.keyCode === 27) { // allow escape to hide picker
-                        hide();
-                    }
+                showMinutes: function () {
+                    widget.find('.timepicker .timepicker-picker').hide();
+                    widget.find('.timepicker .timepicker-minutes').show();
                 },
 
-                change = function (e) {
-                    setValue(parseInputDate($(e.target).val()));
-                    e.stopImmediatePropagation();
-                    return false;
+                showSeconds: function () {
+                    widget.find('.timepicker .timepicker-picker').hide();
+                    widget.find('.timepicker .timepicker-seconds').show();
                 },
 
-                attachDatePickerElementEvents = function () {
-                    if (element.is('input')) {
-                        element.on({
-                            'click': show,
-                            'focus': show,
-                            'change': change,
-                            'blur': hide,
-                            'keydown': keydown
-                        });
-                    } else {
-                        element.on({
-                            'change': change
-                        }, 'input');
-                        if (component) {
-                            component.on('click', toggle);
-                            component.on('mousedown', false);
-                        } else {
-                            element.on('click', show);
-                        }
-                    }
-                },
+                selectHour: function (e) {
+                    var hour = parseInt($(e.target).text(), 10);
 
-                detachDatePickerElementEvents = function () {
-                    if (element.is('input')) {
-                        element.off({
-                            'focus': show,
-                            'change': change,
-                            'blur': hide,
-                            'click': show,
-                            'keydown': keydown
-                        });
-                    } else {
-                        element.off({
-                            'change': change
-                        }, 'input');
-                        if (component) {
-                            component.off('click', toggle);
-                            component.off('mousedown', false);
+                    if (!use24Hours) {
+                        if (date.hours() >= 12) {
+                            if (hour !== 12) {
+                                hour += 12;
+                            }
                         } else {
-                            element.off('click', show);
+                            if (hour === 12) {
+                                hour = 0;
+                            }
                         }
                     }
+                    setValue(date.clone().hours(hour));
+                    actions.showPicker.call(picker);
                 },
 
-                indexGivenDates = function (givenDatesArray) {
-                    // Store given enabledDates and disabledDates as keys.
-                    // This way we can check their existence in O(1) time instead of looping through whole array.
-                    // (for example: options.enabledDates['2014-02-27'] === true)
-                    var givenDatesIndexed = {};
-                    $.each(givenDatesArray, function () {
-                        var dDate = parseInputDate(this);
-                        if (dDate.isValid()) {
-                            givenDatesIndexed[dDate.format('YYYY-MM-DD')] = true;
-                        }
-                    });
-                    return (Object.keys(givenDatesIndexed).length) ? givenDatesIndexed : false;
+                selectMinute: function (e) {
+                    setValue(date.clone().minutes(parseInt($(e.target).text(), 10)));
+                    actions.showPicker.call(picker);
                 },
 
-                format = function (newFormat) {
-                    if (arguments.length === 0) {
-                        return options.format;
-                    }
-
-                    if ((typeof newFormat !== 'string') && ((typeof newFormat !== 'boolean') || (newFormat !== false))) {
-                        throw new TypeError('format() expects a sting or boolean:false parameter ' + newFormat);
-                    }
-
-                    options.format = newFormat;
+                selectSecond: function (e) {
+                    setValue(date.clone().seconds(parseInt($(e.target).text(), 10)));
+                    actions.showPicker.call(picker);
+                },
 
-                    newFormat = newFormat || 'L LT';
+                clear: function () {
+                    setValue(null);
+                },
 
-                    actualFormat = newFormat.replace(/(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, function (input) {
-                        return date.localeData().longDateFormat(input) || input;
-                    });
+                today: function () {
+                    setValue(moment());
+                }
+            },
 
-                    use24hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.indexOf('h') < 1);
+            doAction = function (e) {
+                if ($(e.currentTarget).is('.disabled')) {
+                    return false;
+                }
+                actions[$(e.currentTarget).data('action')].apply(picker, arguments);
+                return false;
+            },
+
+            show = function () {
+                var currentMoment,
+                    useCurrentGranularity = {
+                        'year': function (m) {
+                            return m.month(0).date(1).hours(0).seconds(0).minutes(0);
+                        },
+                        'month': function (m) {
+                            return m.date(1).hours(0).seconds(0).minutes(0);
+                        },
+                        'day': function (m) {
+                            return m.hours(0).seconds(0).minutes(0);
+                        },
+                        'hour': function (m) {
+                            return m.seconds(0).minutes(0);
+                        },
+                        'minute': function (m) {
+                            return m.seconds(0);
+                        }
+                    };
 
-                    if (isEnabled('y')) {
-                        minViewModeNumber = 2;
-                    }
-                    if (isEnabled('M')) {
-                        minViewModeNumber = 1;
-                    }
-                    if (isEnabled('d')) {
-                        minViewModeNumber = 0;
+                if (input.prop('disabled') || input.prop('readonly') || widget) {
+                    return picker;
+                }
+                if (options.useCurrent && unset) { // && input.val().trim().length !== 0) { this broke the jasmine test
+                    currentMoment = moment();
+                    if (typeof options.useCurrent === 'string') {
+                        currentMoment = useCurrentGranularity[options.useCurrent](currentMoment);
                     }
+                    setValue(currentMoment);
+                }
 
-                    currentViewMode = Math.max(minViewModeNumber, currentViewMode);
-
-                    if (!unset) {
-                        setValue(date);
-                    }
-                    return picker;
-                };
+                widget = getTemplate();
 
-            /********************************************************************************
-             *
-             * Public API functions
-             * =====================
-             *
-             * Important: Do not expose direct references to private objects or the options
-             * object to the outer world. Always return a clone when returning values or make
-             * a clone when setting a private variable.
-             *
-             ********************************************************************************/
-            picker.destroy = function () {
-                hide();
-                detachDatePickerElementEvents();
-                element.removeData('DateTimePicker');
-                element.removeData('date');
-            };
+                fillDow();
+                fillMonths();
 
-            picker.toggle = toggle;
+                widget.find('.timepicker-hours').hide();
+                widget.find('.timepicker-minutes').hide();
+                widget.find('.timepicker-seconds').hide();
 
-            picker.show = show;
+                update();
+                showMode();
 
-            picker.hide = hide;
+                $(window).on('resize', place);
+                widget.on('click', '[data-action]', doAction); // this handles clicks on the widget
+                widget.on('mousedown', false);
 
-            picker.disable = function () {
-                hide();
                 if (component && component.hasClass('btn')) {
-                    component.addClass('disabled');
+                    component.toggleClass('active');
                 }
-                input.prop('disabled', true);
-                return picker;
-            };
+                widget.show();
+                place();
 
-            picker.enable = function () {
-                if (component && component.hasClass('btn')) {
-                    component.removeClass('disabled');
+                if (!input.is(':focus')) {
+                    input.focus();
                 }
-                input.prop('disabled', false);
+
+                notifyEvent({
+                    type: 'dp.show'
+                });
                 return picker;
-            };
+            },
+
+            toggle = function () {
+                return (widget ? hide() : show());
+            },
 
-            picker.options = function (newOptions) {
-                if (arguments.length === 0) {
-                    return $.extend(true, {}, options);
+            parseInputDate = function (date) {
+                if (moment.isMoment(date) || date instanceof Date) {
+                    date = moment(date);
+                } else {
+                    date = moment(date, parseFormats, options.useStrict);
                 }
+                date.locale(options.locale);
+                return date;
+            },
 
-                if (!(newOptions instanceof Object)) {
-                    throw new TypeError('options() options parameter should be an object');
+            keydown = function (e) {
+                if (e.keyCode === 27) { // allow escape to hide picker
+                    hide();
                 }
-                $.extend(true, options, newOptions);
-                $.each(options, function (key, value) {
-                    if (picker[key] !== undefined) {
-                        picker[key](value);
-                    } else {
-                        throw new TypeError('option ' + key + ' is not recognized!');
-                    }
+            },
+
+            change = function (e) {
+                var val = $(e.target).val().trim(),
+                    parsedDate = val ? parseInputDate(val) : null;
+                setValue(parsedDate);
+                e.stopImmediatePropagation();
+                return false;
+            },
+
+            attachDatePickerElementEvents = function () {
+                input.on({
+                    'change': change,
+                    'blur': hide,
+                    'keydown': keydown
+                });
+
+                if (element.is('input')) {
+                    input.on({
+                        'focus': show
+                    });
+                } else if (component) {
+                    component.on('click', toggle);
+                    component.on('mousedown', false);
+                }
+            },
+
+            detachDatePickerElementEvents = function () {
+                input.off({
+                    'change': change,
+                    'blur': hide,
+                    'keydown': keydown
                 });
-                return picker;
-            };
 
-            picker.date = function (newDate) {
-                if (arguments.length === 0) {
-                    if (unset || errored) {
-                        return null;
+                if (element.is('input')) {
+                    input.off({
+                        'focus': show
+                    });
+                } else if (component) {
+                    component.off('click', toggle);
+                    component.off('mousedown', false);
+                }
+            },
+
+            indexGivenDates = function (givenDatesArray) {
+                // Store given enabledDates and disabledDates as keys.
+                // This way we can check their existence in O(1) ti

<TRUNCATED>