From 557b657221c0059dca361cdac982001b25152e5e Mon Sep 17 00:00:00 2001 From: Eonasdan Date: Sun, 18 Jan 2015 18:43:12 -0500 Subject: [PATCH] updating to v4 --- CONTRIBUTING.md | 4 +- Gruntfile.js | 53 +- LICENSE | 2 +- README.md | 18 +- bower.json | 8 +- build/css/bootstrap-datetimepicker.css | 263 +- build/css/bootstrap-datetimepicker.min.css | 6 +- build/js/bootstrap-datetimepicker.min.js | 2 +- .../Bootstrap.v3.Datetimepicker.4.0.0.nupkg | Bin 0 -> 23450 bytes ...ootstrap.v3.Datetimepicker.CSS.4.0.0.nupkg | Bin 0 -> 24312 bytes component.json | 5 +- composer.json | 7 +- package.json | 16 +- src/js/bootstrap-datetimepicker.js | 2632 +++++++++-------- src/less/_bootstrap-datetimepicker.less | 307 ++ src/less/bootstrap-datetimepicker-build.less | 14 +- .../Bootstrap.v3.Datetimepicker.CSS.nuspec | 6 +- src/nuget/Bootstrap.v3.Datetimepicker.nuspec | 6 +- test/publicApiSpec.js | 497 ++++ 19 files changed, 2563 insertions(+), 1283 deletions(-) create mode 100644 build/nuget/Bootstrap.v3.Datetimepicker.4.0.0.nupkg create mode 100644 build/nuget/Bootstrap.v3.Datetimepicker.CSS.4.0.0.nupkg create mode 100644 src/less/_bootstrap-datetimepicker.less create mode 100644 test/publicApiSpec.js diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c1d6cc859..c93d9b55d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,7 +1,7 @@ Submitting Issues ================= -If you are submitting a bug, please test and/or fork [this jsfiddle (v3)](http://jsfiddle.net/kmbo576p/) or [this jsfiddle (v4)](http://jsfiddle.net/Eonasdan/0Ltv25o8/) demonstrating the issue. Code issues and fringe case bugs that do not include a jsfiddle (or similar) will be closed. +If you are submitting a bug, please test and/or fork [this jsfiddle](http://jsfiddle.net/d3wCU/) demonstrating the issue. Code issues and fringe case bugs that do not include a jsfiddle (or similar) will be closed. Contributing code ================= @@ -20,7 +20,7 @@ grunt # this runs tests and jshint Very important notes ==================== - * **Pull requests to the `master` branch will be closed.** Please submit all pull requests to the `development` branch. + * **Pull pull requests to the `master` branch will be closed.** Please submit all pull requests to the `development` branch. * **Do not include the minified files in your pull request.** Don't worry, we'll build them when we cut a release. Grunt tasks diff --git a/Gruntfile.js b/Gruntfile.js index cf1ade14c..9aa026ca4 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -24,11 +24,12 @@ module.exports = function (grunt) { jshint: { all: [ - 'Gruntfile.js', 'src/js/*.js' + 'Gruntfile.js', 'src/js/*.js', 'test/*.js' ], options: { 'browser' : true, 'node' : true, + 'jquery' : true, 'boss' : false, 'curly' : true, 'debug' : false, @@ -57,15 +58,24 @@ module.exports = function (grunt) { 'quotmark' : 'single', 'globals': { 'define': false, - 'jQuery': false, - 'moment': false + 'moment': false, + // Jasmine + 'jasmine': false, + 'describe': false, + 'xdescribe': false, + 'expect': false, + 'it': false, + 'xit': false, + 'spyOn': false, + 'beforeEach': false, + 'afterEach': false } } }, jscs: { all: [ - 'Gruntfile.js', 'src/js/*.js' + 'Gruntfile.js', 'src/js/*.js', 'test/*.js' ], options: { config: '.jscs.json' @@ -86,22 +96,49 @@ module.exports = function (grunt) { 'build/css/bootstrap-datetimepicker.css': 'src/less/bootstrap-datetimepicker-build.less' } } + }, + + jasmine: { + customTemplate: { + src: 'src/js/*.js', + options: { + specs: 'test/*Spec.js', + helpers: 'test/*Helper.js', + styles: [ + 'node_modules/bootstrap/dist/css/bootstrap.min.css', + 'build/css/bootstrap-datetimepicker.min.css' + ], + vendor: [ + 'node_modules/jquery/dist/jquery.min.js', + 'node_modules/moment/min/moment-with-locales.min.js', + 'node_modules/bootstrap/dist/js/bootstrap.min.js' + ], + display: 'none', + summary: 'true' + } + } } }); grunt.loadTasks('tasks'); + grunt.loadNpmTasks('grunt-contrib-jasmine'); + // These plugins provide necessary tasks. require('load-grunt-tasks')(grunt); // Default task. - grunt.registerTask('default', ['jshint', 'jscs']); + grunt.registerTask('default', ['jshint', 'jscs', 'less', 'jasmine']); // travis build task grunt.registerTask('build:travis', [ // code style - 'jshint', 'jscs' + 'jshint', 'jscs', + // build + 'uglify', 'less', + // tests + 'jasmine' ]); // Task to be run when building @@ -131,7 +168,7 @@ module.exports = function (grunt) { done(); }); } - else { + else { //--target=css grunt.util.spawn({ cmd: 'src/nuget/nuget.exe', args: [ @@ -152,4 +189,6 @@ module.exports = function (grunt) { }); } }); + + grunt.registerTask('test', ['jshint', 'jscs', 'uglify', 'less', 'jasmine']); }; diff --git a/LICENSE b/LICENSE index 47f5de70e..f8071d73e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2014 Eonasdan, nikoskalogridis +Copyright (c) 2015 Jonathan Peterson (@Eonasdan) Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 9e85c8a49..5889c02a2 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,25 @@ -# Bootstrap 3 datetimepicker widget +# Bootstrap 3 Date/Time Picker ![GitHub version](https://badge.fury.io/gh/Eonasdan%2Fbootstrap-datetimepicker.png)   ![Travis](https://travis-ci.org/Eonasdan/bootstrap-datetimepicker.svg?branch=development) ![DateTimePicker](http://i.imgur.com/nfnvh5g.png) ## [View the manual and demos](http://eonasdan.github.io/bootstrap-datetimepicker/) -#Feature Freeze -Version 3 of our date picker is currently in a feature freeze. Version 4 is comming very soon. We are working on updating the docs and getting existing bugs and features rolled up into v4. We will continue to fix minor bugs in v3 in the meantime, but all new features should go into v4. +#v4 +v4 is out now! For v4 related bugs and issues see: /Eonasdan/bootstrap-datetimepicker/labels/v4. + +v3 is going into an archive state. Please be sure to check the documents. v4 has breaking changes and is a major rewrite. ## Submitting Issues -Please test and/or fork [this jsfiddle](http://jsfiddle.net/Eonasdan/f3x2mvr1/) with an example of your issue before you post an issue here. +If you have issues, please check the following first: +* Have you read the docs? +* Do you have the latest version of momentjs? +* Do you have the latest version of jQuery? +* Please test and/or fork [this jsfiddle](http://jsfiddle.net/Eonasdan/0Ltv25o8/) with an example of your issue before you post an issue here. ## Where do you use this? I'd love to know if your public site is using this plugin and list your logo on the documentation site. Please email me `eonasdan at outlook dot com`. Do not submit issue/feature request to this email, they will be ignored. ## [Installation instructions](https://github.com/Eonasdan/bootstrap-datetimepicker/wiki/Installation) -Installation instructions has been moved to the wiki -## [Change Log](https://github.com/Eonasdan/bootstrap-datetimepicker/wiki/Change-Log) -The change log has moved to the wiki +## [Change Log](https://github.com/Eonasdan/bootstrap-datetimepicker/wiki/Version-4-changelog) \ No newline at end of file diff --git a/bower.json b/bower.json index 8e9d1603d..7985e7e38 100644 --- a/bower.json +++ b/bower.json @@ -1,13 +1,15 @@ { "name": "eonasdan-bootstrap-datetimepicker", - "version": "3.1.3", + "version": "4.0.0", "main": [ "build/css/bootstrap-datetimepicker.min.css", - "build/js/bootstrap-datetimepicker.min.js" + "build/js/bootstrap-datetimepicker.min.js", + "src/less/_bootstrap-datetimepicker.less", + "src/less/bootstrap-datetimepicker-build.less", + "src/js/bootstrap-datetimepicker.js" ], "dependencies": { "jquery": ">=1.8.3", - "bootstrap": "~3.0", "moment": ">=2.8.0" }, "homepage": "https://github.com/Eonasdan/bootstrap-datetimepicker", diff --git a/build/css/bootstrap-datetimepicker.css b/build/css/bootstrap-datetimepicker.css index bd37b08b3..590fca133 100644 --- a/build/css/bootstrap-datetimepicker.css +++ b/build/css/bootstrap-datetimepicker.css @@ -1,75 +1,73 @@ /*! - * Datetimepicker for Bootstrap v3 -//! version : 3.1.3 + * Datetimepicker for Bootstrap 3 +//! version : 4.0.0-beta * https://github.com/Eonasdan/bootstrap-datetimepicker/ */ -.bootstrap-datetimepicker-widget { - top: 0; - left: 0; - width: 250px; +.bootstrap-datetimepicker-widget.dropdown-menu { + margin: 2px 0; padding: 4px; - margin-top: 1px; - z-index: 99999 !important; - border-radius: 4px; + width: 19em; +} +@media (min-width: 768px) { + .bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs { + width: 38em; + } } -.bootstrap-datetimepicker-widget.timepicker-sbs { - width: 600px; +@media (min-width: 992px) { + .bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs { + width: 38em; + } } -.bootstrap-datetimepicker-widget.bottom:before { +@media (min-width: 1200px) { + .bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs { + width: 38em; + } +} +.bootstrap-datetimepicker-widget.dropdown-menu:before, +.bootstrap-datetimepicker-widget.dropdown-menu:after { content: ''; display: inline-block; + position: absolute; +} +.bootstrap-datetimepicker-widget.dropdown-menu.bottom:before { border-left: 7px solid transparent; border-right: 7px solid transparent; border-bottom: 7px solid #ccc; border-bottom-color: rgba(0, 0, 0, 0.2); - position: absolute; top: -7px; left: 7px; } -.bootstrap-datetimepicker-widget.bottom:after { - content: ''; - display: inline-block; +.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after { border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 6px solid white; - position: absolute; top: -6px; left: 8px; } -.bootstrap-datetimepicker-widget.top:before { - content: ''; - display: inline-block; +.bootstrap-datetimepicker-widget.dropdown-menu.top:before { border-left: 7px solid transparent; border-right: 7px solid transparent; border-top: 7px solid #ccc; border-top-color: rgba(0, 0, 0, 0.2); - position: absolute; bottom: -7px; left: 6px; } -.bootstrap-datetimepicker-widget.top:after { - content: ''; - display: inline-block; +.bootstrap-datetimepicker-widget.dropdown-menu.top:after { border-left: 6px solid transparent; border-right: 6px solid transparent; border-top: 6px solid white; - position: absolute; bottom: -6px; left: 7px; } -.bootstrap-datetimepicker-widget .dow { - width: 14.2857%; -} -.bootstrap-datetimepicker-widget.pull-right:before { +.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:before { left: auto; right: 6px; } -.bootstrap-datetimepicker-widget.pull-right:after { +.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:after { left: auto; right: 7px; } -.bootstrap-datetimepicker-widget > ul { - list-style-type: none; +.bootstrap-datetimepicker-widget .list-unstyled { margin: 0; } .bootstrap-datetimepicker-widget a[data-action] { @@ -89,17 +87,109 @@ .bootstrap-datetimepicker-widget button[data-action] { padding: 6px; } -.bootstrap-datetimepicker-widget table[data-hour-format="12"] .separator { - width: 4px; +.bootstrap-datetimepicker-widget .btn[data-action="incrementHours"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; padding: 0; - margin: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Increment Hours"; +} +.bootstrap-datetimepicker-widget .btn[data-action="incrementMinutes"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Increment Minutes"; } -.bootstrap-datetimepicker-widget .datepicker > div { - display: none; +.bootstrap-datetimepicker-widget .btn[data-action="decrementHours"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Decrement Hours"; +} +.bootstrap-datetimepicker-widget .btn[data-action="decrementMinutes"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Decrement Minutes"; +} +.bootstrap-datetimepicker-widget .btn[data-action="showHours"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Show Hours"; +} +.bootstrap-datetimepicker-widget .btn[data-action="showMinutes"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Show Minutes"; +} +.bootstrap-datetimepicker-widget .btn[data-action="togglePeriod"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Toggle AM/PM"; } .bootstrap-datetimepicker-widget .picker-switch { text-align: center; } +.bootstrap-datetimepicker-widget .picker-switch::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Toggle Date and Time Screens"; +} +.bootstrap-datetimepicker-widget .picker-switch td { + padding: 0; + margin: 0; + height: auto; + width: auto; + line-height: inherit; +} +.bootstrap-datetimepicker-widget .picker-switch td span { + line-height: 2.5; + height: 2.5em; + width: 100%; +} .bootstrap-datetimepicker-widget table { width: 100%; margin: 0; @@ -109,13 +199,55 @@ text-align: center; border-radius: 4px; } +.bootstrap-datetimepicker-widget th { + height: 20px; + line-height: 20px; + width: 20px; +} +.bootstrap-datetimepicker-widget th.picker-switch { + width: 145px; +} +.bootstrap-datetimepicker-widget th.disabled, +.bootstrap-datetimepicker-widget th.disabled:hover { + background: none; + color: #777777; + cursor: not-allowed; +} +.bootstrap-datetimepicker-widget th.prev::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Previous Month"; +} +.bootstrap-datetimepicker-widget th.next::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Next Month"; +} +.bootstrap-datetimepicker-widget thead tr:first-child th { + cursor: pointer; +} +.bootstrap-datetimepicker-widget thead tr:first-child th:hover { + background: #eeeeee; +} .bootstrap-datetimepicker-widget td { height: 54px; line-height: 54px; width: 54px; } .bootstrap-datetimepicker-widget td.cw { - font-size: 10px; + font-size: .8em; height: 20px; line-height: 20px; color: #777777; @@ -190,49 +322,20 @@ color: #777777; cursor: not-allowed; } -.bootstrap-datetimepicker-widget th { - height: 20px; - line-height: 20px; - width: 20px; +.bootstrap-datetimepicker-widget.usetwentyfour td.hour { + height: 27px; + line-height: 27px; } -.bootstrap-datetimepicker-widget th.picker-switch { - width: 145px; -} -.bootstrap-datetimepicker-widget th.next, -.bootstrap-datetimepicker-widget th.prev { - font-size: 21px; -} -.bootstrap-datetimepicker-widget th.disabled, -.bootstrap-datetimepicker-widget th.disabled:hover { - background: none; - color: #777777; - cursor: not-allowed; -} -.bootstrap-datetimepicker-widget thead tr:first-child th { +.input-group.date .input-group-addon { cursor: pointer; } -.bootstrap-datetimepicker-widget thead tr:first-child th:hover { - background: #eeeeee; -} -.input-group.date .input-group-addon span { - display: block; - cursor: pointer; - width: 16px; - height: 16px; -} -.bootstrap-datetimepicker-widget.left-oriented:before { - left: auto; - right: 6px; -} -.bootstrap-datetimepicker-widget.left-oriented:after { - left: auto; - right: 7px; -} -.bootstrap-datetimepicker-widget ul.list-unstyled li div.timepicker div.timepicker-picker table.table-condensed tbody > tr > td { - padding: 0px !important; -} -@media screen and (max-width: 767px) { - .bootstrap-datetimepicker-widget.timepicker-sbs { - width: 283px; - } +.sr-only { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; } diff --git a/build/css/bootstrap-datetimepicker.min.css b/build/css/bootstrap-datetimepicker.min.css index cf838a3c2..13473f3b3 100644 --- a/build/css/bootstrap-datetimepicker.min.css +++ b/build/css/bootstrap-datetimepicker.min.css @@ -1,5 +1,5 @@ /*! - * Datetimepicker for Bootstrap v3 -//! version : 3.1.3 + * Datetimepicker for Bootstrap 3 +//! version : 4.0.0-beta * https://github.com/Eonasdan/bootstrap-datetimepicker/ - */.bootstrap-datetimepicker-widget{top:0;left:0;width:250px;padding:4px;margin-top:1px;z-index:99999!important;border-radius:4px}.bootstrap-datetimepicker-widget.timepicker-sbs{width:600px}.bootstrap-datetimepicker-widget.bottom:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);position:absolute;top:-7px;left:7px}.bootstrap-datetimepicker-widget.bottom:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;position:absolute;top:-6px;left:8px}.bootstrap-datetimepicker-widget.top:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);position:absolute;bottom:-7px;left:6px}.bootstrap-datetimepicker-widget.top:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #fff;position:absolute;bottom:-6px;left:7px}.bootstrap-datetimepicker-widget .dow{width:14.2857%}.bootstrap-datetimepicker-widget.pull-right:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.pull-right:after{left:auto;right:7px}.bootstrap-datetimepicker-widget>ul{list-style-type:none;margin:0}.bootstrap-datetimepicker-widget a[data-action]{padding:6px 0}.bootstrap-datetimepicker-widget a[data-action]:active{box-shadow:none}.bootstrap-datetimepicker-widget .timepicker-hour,.bootstrap-datetimepicker-widget .timepicker-minute,.bootstrap-datetimepicker-widget .timepicker-second{width:54px;font-weight:700;font-size:1.2em;margin:0}.bootstrap-datetimepicker-widget button[data-action]{padding:6px}.bootstrap-datetimepicker-widget table[data-hour-format="12"] .separator{width:4px;padding:0;margin:0}.bootstrap-datetimepicker-widget .datepicker>div{display:none}.bootstrap-datetimepicker-widget .picker-switch{text-align:center}.bootstrap-datetimepicker-widget table{width:100%;margin:0}.bootstrap-datetimepicker-widget td,.bootstrap-datetimepicker-widget th{text-align:center;border-radius:4px}.bootstrap-datetimepicker-widget td{height:54px;line-height:54px;width:54px}.bootstrap-datetimepicker-widget td.cw{font-size:10px;height:20px;line-height:20px;color:#777}.bootstrap-datetimepicker-widget td.day{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget td.day:hover,.bootstrap-datetimepicker-widget td.hour:hover,.bootstrap-datetimepicker-widget td.minute:hover,.bootstrap-datetimepicker-widget td.second:hover{background:#eee;cursor:pointer}.bootstrap-datetimepicker-widget td.old,.bootstrap-datetimepicker-widget td.new{color:#777}.bootstrap-datetimepicker-widget td.today{position:relative}.bootstrap-datetimepicker-widget td.today:before{content:'';display:inline-block;border-left:7px solid transparent;border-bottom:7px solid #428bca;border-top-color:rgba(0,0,0,.2);position:absolute;bottom:4px;right:4px}.bootstrap-datetimepicker-widget td.active,.bootstrap-datetimepicker-widget td.active:hover{background-color:#428bca;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.bootstrap-datetimepicker-widget td.active.today:before{border-bottom-color:#fff}.bootstrap-datetimepicker-widget td.disabled,.bootstrap-datetimepicker-widget td.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget td span{display:inline-block;width:54px;height:54px;line-height:54px;margin:2px 1.5px;cursor:pointer;border-radius:4px}.bootstrap-datetimepicker-widget td span:hover{background:#eee}.bootstrap-datetimepicker-widget td span.active{background-color:#428bca;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.bootstrap-datetimepicker-widget td span.old{color:#777}.bootstrap-datetimepicker-widget td span.disabled,.bootstrap-datetimepicker-widget td span.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget th{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget th.picker-switch{width:145px}.bootstrap-datetimepicker-widget th.next,.bootstrap-datetimepicker-widget th.prev{font-size:21px}.bootstrap-datetimepicker-widget th.disabled,.bootstrap-datetimepicker-widget th.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget thead tr:first-child th{cursor:pointer}.bootstrap-datetimepicker-widget thead tr:first-child th:hover{background:#eee}.input-group.date .input-group-addon span{display:block;cursor:pointer;width:16px;height:16px}.bootstrap-datetimepicker-widget.left-oriented:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.left-oriented:after{left:auto;right:7px}.bootstrap-datetimepicker-widget ul.list-unstyled li div.timepicker div.timepicker-picker table.table-condensed tbody>tr>td{padding:0!important}@media screen and (max-width:767px){.bootstrap-datetimepicker-widget.timepicker-sbs{width:283px}} \ No newline at end of file + */.bootstrap-datetimepicker-widget.dropdown-menu{margin:2px 0;padding:4px;width:19em}@media (min-width:768px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}@media (min-width:992px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}@media (min-width:1200px){.bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs{width:38em}}.bootstrap-datetimepicker-widget.dropdown-menu:before,.bootstrap-datetimepicker-widget.dropdown-menu:after{content:'';display:inline-block;position:absolute}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:before{border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0,0,0,.2);top:-7px;left:7px}.bootstrap-datetimepicker-widget.dropdown-menu.bottom:after{border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #fff;top:-6px;left:8px}.bootstrap-datetimepicker-widget.dropdown-menu.top:before{border-left:7px solid transparent;border-right:7px solid transparent;border-top:7px solid #ccc;border-top-color:rgba(0,0,0,.2);bottom:-7px;left:6px}.bootstrap-datetimepicker-widget.dropdown-menu.top:after{border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid #fff;bottom:-6px;left:7px}.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:before{left:auto;right:6px}.bootstrap-datetimepicker-widget.dropdown-menu.pull-right:after{left:auto;right:7px}.bootstrap-datetimepicker-widget .list-unstyled{margin:0}.bootstrap-datetimepicker-widget a[data-action]{padding:6px 0}.bootstrap-datetimepicker-widget a[data-action]:active{box-shadow:none}.bootstrap-datetimepicker-widget .timepicker-hour,.bootstrap-datetimepicker-widget .timepicker-minute,.bootstrap-datetimepicker-widget .timepicker-second{width:54px;font-weight:700;font-size:1.2em;margin:0}.bootstrap-datetimepicker-widget button[data-action]{padding:6px}.bootstrap-datetimepicker-widget .btn[data-action=incrementHours]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0;content:"Increment Hours"}.bootstrap-datetimepicker-widget .btn[data-action=incrementMinutes]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0;content:"Increment Minutes"}.bootstrap-datetimepicker-widget .btn[data-action=decrementHours]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0;content:"Decrement Hours"}.bootstrap-datetimepicker-widget .btn[data-action=decrementMinutes]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0;content:"Decrement Minutes"}.bootstrap-datetimepicker-widget .btn[data-action=showHours]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0;content:"Show Hours"}.bootstrap-datetimepicker-widget .btn[data-action=showMinutes]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0;content:"Show Minutes"}.bootstrap-datetimepicker-widget .btn[data-action=togglePeriod]::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0;content:"Toggle AM/PM"}.bootstrap-datetimepicker-widget .picker-switch{text-align:center}.bootstrap-datetimepicker-widget .picker-switch::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0;content:"Toggle Date and Time Screens"}.bootstrap-datetimepicker-widget .picker-switch td{padding:0;margin:0;height:auto;width:auto;line-height:inherit}.bootstrap-datetimepicker-widget .picker-switch td span{line-height:2.5;height:2.5em;width:100%}.bootstrap-datetimepicker-widget table{width:100%;margin:0}.bootstrap-datetimepicker-widget td,.bootstrap-datetimepicker-widget th{text-align:center;border-radius:4px}.bootstrap-datetimepicker-widget th{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget th.picker-switch{width:145px}.bootstrap-datetimepicker-widget th.disabled,.bootstrap-datetimepicker-widget th.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget th.prev::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0;content:"Previous Month"}.bootstrap-datetimepicker-widget th.next::after{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0;content:"Next Month"}.bootstrap-datetimepicker-widget thead tr:first-child th{cursor:pointer}.bootstrap-datetimepicker-widget thead tr:first-child th:hover{background:#eee}.bootstrap-datetimepicker-widget td{height:54px;line-height:54px;width:54px}.bootstrap-datetimepicker-widget td.cw{font-size:.8em;height:20px;line-height:20px;color:#777}.bootstrap-datetimepicker-widget td.day{height:20px;line-height:20px;width:20px}.bootstrap-datetimepicker-widget td.day:hover,.bootstrap-datetimepicker-widget td.hour:hover,.bootstrap-datetimepicker-widget td.minute:hover,.bootstrap-datetimepicker-widget td.second:hover{background:#eee;cursor:pointer}.bootstrap-datetimepicker-widget td.old,.bootstrap-datetimepicker-widget td.new{color:#777}.bootstrap-datetimepicker-widget td.today{position:relative}.bootstrap-datetimepicker-widget td.today:before{content:'';display:inline-block;border-left:7px solid transparent;border-bottom:7px solid #428bca;border-top-color:rgba(0,0,0,.2);position:absolute;bottom:4px;right:4px}.bootstrap-datetimepicker-widget td.active,.bootstrap-datetimepicker-widget td.active:hover{background-color:#428bca;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.bootstrap-datetimepicker-widget td.active.today:before{border-bottom-color:#fff}.bootstrap-datetimepicker-widget td.disabled,.bootstrap-datetimepicker-widget td.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget td span{display:inline-block;width:54px;height:54px;line-height:54px;margin:2px 1.5px;cursor:pointer;border-radius:4px}.bootstrap-datetimepicker-widget td span:hover{background:#eee}.bootstrap-datetimepicker-widget td span.active{background-color:#428bca;color:#fff;text-shadow:0 -1px 0 rgba(0,0,0,.25)}.bootstrap-datetimepicker-widget td span.old{color:#777}.bootstrap-datetimepicker-widget td span.disabled,.bootstrap-datetimepicker-widget td span.disabled:hover{background:0 0;color:#777;cursor:not-allowed}.bootstrap-datetimepicker-widget.usetwentyfour td.hour{height:27px;line-height:27px}.input-group.date .input-group-addon{cursor:pointer}.sr-only{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);border:0} \ No newline at end of file diff --git a/build/js/bootstrap-datetimepicker.min.js b/build/js/bootstrap-datetimepicker.min.js index cdba4b105..5fdddb3cf 100644 --- a/build/js/bootstrap-datetimepicker.min.js +++ b/build/js/bootstrap-datetimepicker.min.js @@ -1 +1 @@ -!function(a,b){"use strict";if("function"==typeof define&&define.amd)define(["jquery","moment"],b);else if("object"==typeof exports)b(require("jquery"),require("moment"));else{if(!jQuery)throw new Error("bootstrap-datetimepicker requires jQuery to be loaded first");if(!moment)throw new Error("bootstrap-datetimepicker requires moment.js to be loaded first");b(a.jQuery,moment)}}(this,function(a,b){"use strict";if("undefined"==typeof b)throw new Error("momentjs is required");var c=0,d=function(d,e){var f,g=a.fn.datetimepicker.defaults,h={time:"glyphicon glyphicon-time",date:"glyphicon glyphicon-calendar",up:"glyphicon glyphicon-chevron-up",down:"glyphicon glyphicon-chevron-down"},i=this,j=!1,k=function(){var f,j,k=!1;if(i.options=a.extend({},g,e),i.options.icons=a.extend({},h,i.options.icons),i.element=a(d),m(),!i.options.pickTime&&!i.options.pickDate)throw new Error("Must choose at least one picker");if(i.id=c++,b.locale(i.options.language),i.date=b(),i.unset=!1,i.isInput=i.element.is("input"),i.component=!1,i.element.hasClass("input-group")&&(i.component=i.element.find(0===i.element.find(".datepickerbutton").size()?'[class^="input-group-"]':".datepickerbutton")),i.format=i.options.format,f=b().localeData(),i.format||(i.format=i.options.pickDate?f.longDateFormat("L"):"",i.options.pickDate&&i.options.pickTime&&(i.format+=" "),i.format+=i.options.pickTime?f.longDateFormat("LT"):"",i.options.useSeconds&&(-1!==f.longDateFormat("LT").indexOf(" A")?i.format=i.format.split(" A")[0]+":ss A":i.format+=":ss")),i.use24hours=i.format.toLowerCase().indexOf("a")<0&&i.format.indexOf("h")<0,i.component&&(k=i.component.find("span")),i.options.pickTime&&k&&k.addClass(i.options.icons.time),i.options.pickDate&&k&&(k.removeClass(i.options.icons.time),k.addClass(i.options.icons.date)),i.options.widgetParent="string"==typeof i.options.widgetParent&&i.options.widgetParent||i.element.parents().filter(function(){return"scroll"===a(this).css("overflow-y")}).get(0)||"body",i.widget=a(Q()).appendTo(i.options.widgetParent),i.minViewMode=i.options.minViewMode||0,"string"==typeof i.minViewMode)switch(i.minViewMode){case"months":i.minViewMode=1;break;case"years":i.minViewMode=2;break;default:i.minViewMode=0}if(i.viewMode=i.options.viewMode||0,"string"==typeof i.viewMode)switch(i.viewMode){case"months":i.viewMode=1;break;case"years":i.viewMode=2;break;default:i.viewMode=0}i.viewMode=Math.max(i.viewMode,i.minViewMode),i.options.disabledDates=O(i.options.disabledDates),i.options.enabledDates=O(i.options.enabledDates),i.startViewMode=i.viewMode,i.setMinDate(i.options.minDate),i.setMaxDate(i.options.maxDate),r(),s(),u(),v(),w(),q(),E(),l().prop("disabled")||F(),""!==i.options.defaultDate&&""===l().val()&&i.setValue(i.options.defaultDate),1!==i.options.minuteStepping&&(j=i.options.minuteStepping,i.date.minutes(Math.round(i.date.minutes()/j)*j%60).seconds(0))},l=function(){var a;if(i.isInput)return i.element;if(a=i.element.find(".datepickerinput"),0===a.size())a=i.element.find("input");else if(!a.is("input"))throw new Error('CSS class "datepickerinput" cannot be applied to non input element');return a},m=function(){var a;a=i.element.is("input")?i.element.data():i.element.find("input").data(),void 0!==a.dateFormat&&(i.options.format=a.dateFormat),void 0!==a.datePickdate&&(i.options.pickDate=a.datePickdate),void 0!==a.datePicktime&&(i.options.pickTime=a.datePicktime),void 0!==a.dateUseminutes&&(i.options.useMinutes=a.dateUseminutes),void 0!==a.dateUseseconds&&(i.options.useSeconds=a.dateUseseconds),void 0!==a.dateUsecurrent&&(i.options.useCurrent=a.dateUsecurrent),void 0!==a.calendarWeeks&&(i.options.calendarWeeks=a.calendarWeeks),void 0!==a.dateMinutestepping&&(i.options.minuteStepping=a.dateMinutestepping),void 0!==a.dateMindate&&(i.options.minDate=a.dateMindate),void 0!==a.dateMaxdate&&(i.options.maxDate=a.dateMaxdate),void 0!==a.dateShowtoday&&(i.options.showToday=a.dateShowtoday),void 0!==a.dateCollapse&&(i.options.collapse=a.dateCollapse),void 0!==a.dateLanguage&&(i.options.language=a.dateLanguage),void 0!==a.dateDefaultdate&&(i.options.defaultDate=a.dateDefaultdate),void 0!==a.dateDisableddates&&(i.options.disabledDates=a.dateDisableddates),void 0!==a.dateEnableddates&&(i.options.enabledDates=a.dateEnableddates),void 0!==a.dateIcons&&(i.options.icons=a.dateIcons),void 0!==a.dateUsestrict&&(i.options.useStrict=a.dateUsestrict),void 0!==a.dateDirection&&(i.options.direction=a.dateDirection),void 0!==a.dateSidebyside&&(i.options.sideBySide=a.dateSidebyside),void 0!==a.dateDaysofweekdisabled&&(i.options.daysOfWeekDisabled=a.dateDaysofweekdisabled)},n=function(){var b,c="absolute",d=i.component?i.component.offset():i.element.offset(),e=a(window);i.width=i.component?i.component.outerWidth():i.element.outerWidth(),d.top=d.top+i.element.outerHeight(),"up"===i.options.direction?b="top":"bottom"===i.options.direction?b="bottom":"auto"===i.options.direction&&(b=d.top+i.widget.height()>e.height()+e.scrollTop()&&i.widget.height()+i.element.outerHeight()"),e=b.weekdaysMin();if(i.options.calendarWeeks===!0&&d.append('#'),0===b().localeData()._week.dow)for(c=0;7>c;c++)d.append(''+e[c]+"");else for(c=1;8>c;c++)d.append(7===c?''+e[0]+"":''+e[c]+"");i.widget.find(".datepicker-days thead").append(d)},s=function(){b.locale(i.options.language);var a,c="",d=b.monthsShort();for(a=0;12>a;a++)c+=''+d[a]+"";i.widget.find(".datepicker-months td").append(c)},t=function(){if(i.options.pickDate){b.locale(i.options.language);var c,d,e,f,g,h,j,k,l,m=i.viewDate.year(),n=i.viewDate.month(),o=i.options.minDate.year(),p=i.options.minDate.month(),q=i.options.maxDate.year(),r=i.options.maxDate.month(),s=[],t=b.months();for(i.widget.find(".datepicker-days").find(".disabled").removeClass("disabled"),i.widget.find(".datepicker-months").find(".disabled").removeClass("disabled"),i.widget.find(".datepicker-years").find(".disabled").removeClass("disabled"),i.widget.find(".datepicker-days th:eq(1)").text(t[n]+" "+m),d=b(i.viewDate,i.format,i.options.useStrict).subtract(1,"months"),j=d.daysInMonth(),d.date(j).startOf("week"),(m===o&&p>=n||o>m)&&i.widget.find(".datepicker-days th:eq(0)").addClass("disabled"),(m===q&&n>=r||m>q)&&i.widget.find(".datepicker-days th:eq(2)").addClass("disabled"),e=b(d).add(42,"d");d.isBefore(e);){if(d.weekday()===b().startOf("week").weekday()&&(f=a(""),s.push(f),i.options.calendarWeeks===!0&&f.append(''+d.week()+"")),g="",d.year()m||d.year()===m&&d.month()>n)&&(g+=" new"),d.isSame(b({y:i.date.year(),M:i.date.month(),d:i.date.date()}))&&(g+=" active"),(M(d,"day")||!N(d))&&(g+=" disabled"),i.options.showToday===!0&&d.isSame(b(),"day")&&(g+=" today"),i.options.daysOfWeekDisabled)for(h=0;h'+d.date()+""),c=d.date(),d.add(1,"d"),c===d.date()&&d.add(1,"d")}for(i.widget.find(".datepicker-days tbody").empty().append(s),l=i.date.year(),t=i.widget.find(".datepicker-months").find("th:eq(1)").text(m).end().find("span").removeClass("active"),l===m&&t.eq(i.date.month()).addClass("active"),o>m-1&&i.widget.find(".datepicker-months th:eq(0)").addClass("disabled"),m+1>q&&i.widget.find(".datepicker-months th:eq(2)").addClass("disabled"),h=0;12>h;h++)m===o&&p>h||o>m?a(t[h]).addClass("disabled"):(m===q&&h>r||m>q)&&a(t[h]).addClass("disabled");for(s="",m=10*parseInt(m/10,10),k=i.widget.find(".datepicker-years").find("th:eq(1)").text(m+"-"+(m+9)).parents("table").find("td"),i.widget.find(".datepicker-years").find("th").removeClass("disabled"),o>m&&i.widget.find(".datepicker-years").find("th:eq(0)").addClass("disabled"),m+9>q&&i.widget.find(".datepicker-years").find("th:eq(2)").addClass("disabled"),m-=1,h=-1;11>h;h++)s+='m||m>q?" disabled":"")+'">'+m+"",m+=1;k.html(s)}},u=function(){b.locale(i.options.language);var a,c,d,e=i.widget.find(".timepicker .timepicker-hours table"),f="";if(e.parent().hide(),i.use24hours)for(a=0,c=0;6>c;c+=1){for(f+="",d=0;4>d;d+=1)f+=''+P(a.toString())+"",a++;f+=""}else for(a=1,c=0;3>c;c+=1){for(f+="",d=0;4>d;d+=1)f+=''+P(a.toString())+"",a++;f+=""}e.html(f)},v=function(){var a,b,c=i.widget.find(".timepicker .timepicker-minutes table"),d="",e=0,f=i.options.minuteStepping;for(c.parent().hide(),1===f&&(f=5),a=0;ab;b+=1)60>e?(d+=''+P(e.toString())+"",e+=f):d+="";d+=""}c.html(d)},w=function(){var a,b,c=i.widget.find(".timepicker .timepicker-seconds table"),d="",e=0;for(c.parent().hide(),a=0;3>a;a++){for(d+="",b=0;4>b;b+=1)d+=''+P(e.toString())+"",e+=5;d+=""}c.html(d)},x=function(){if(i.date){var a=i.widget.find(".timepicker span[data-time-component]"),b=i.date.hours(),c=i.date.format("A");i.use24hours||(0===b?b=12:12!==b&&(b%=12),i.widget.find(".timepicker [data-action=togglePeriod]").text(c)),a.filter("[data-time-component=hours]").text(P(b)),a.filter("[data-time-component=minutes]").text(P(i.date.minutes())),a.filter("[data-time-component=seconds]").text(P(i.date.second()))}},y=function(c){c.stopPropagation(),c.preventDefault(),i.unset=!1;var d,e,f,g,h=a(c.target).closest("span, td, th"),j=b(i.date);if(1===h.length&&!h.is(".disabled"))switch(h[0].nodeName.toLowerCase()){case"th":switch(h[0].className){case"picker-switch":E(1);break;case"prev":case"next":f=R.modes[i.viewMode].navStep,"prev"===h[0].className&&(f=-1*f),i.viewDate.add(f,R.modes[i.viewMode].navFnc),t()}break;case"span":h.is(".month")?(d=h.parent().find("span").index(h),i.viewDate.month(d)):(e=parseInt(h.text(),10)||0,i.viewDate.year(e)),i.viewMode===i.minViewMode&&(i.date=b({y:i.viewDate.year(),M:i.viewDate.month(),d:i.viewDate.date(),h:i.date.hours(),m:i.date.minutes(),s:i.date.seconds()}),K(),o(j,c.type)),E(-1),t();break;case"td":h.is(".day")&&(g=parseInt(h.text(),10)||1,d=i.viewDate.month(),e=i.viewDate.year(),h.is(".old")?0===d?(d=11,e-=1):d-=1:h.is(".new")&&(11===d?(d=0,e+=1):d+=1),i.date=b({y:e,M:d,d:g,h:i.date.hours(),m:i.date.minutes(),s:i.date.seconds()}),i.viewDate=b({y:e,M:d,d:Math.min(28,g)}),t(),K(),o(j,c.type))}},z={incrementHours:function(){L("add","hours",1)},incrementMinutes:function(){L("add","minutes",i.options.minuteStepping)},incrementSeconds:function(){L("add","seconds",1)},decrementHours:function(){L("subtract","hours",1)},decrementMinutes:function(){L("subtract","minutes",i.options.minuteStepping)},decrementSeconds:function(){L("subtract","seconds",1)},togglePeriod:function(){var a=i.date.hours();a>=12?a-=12:a+=12,i.date.hours(a)},showPicker:function(){i.widget.find(".timepicker > div:not(.timepicker-picker)").hide(),i.widget.find(".timepicker .timepicker-picker").show()},showHours:function(){i.widget.find(".timepicker .timepicker-picker").hide(),i.widget.find(".timepicker .timepicker-hours").show()},showMinutes:function(){i.widget.find(".timepicker .timepicker-picker").hide(),i.widget.find(".timepicker .timepicker-minutes").show()},showSeconds:function(){i.widget.find(".timepicker .timepicker-picker").hide(),i.widget.find(".timepicker .timepicker-seconds").show()},selectHour:function(b){var c=parseInt(a(b.target).text(),10);i.use24hours||(i.date.hours()>=12?12!==c&&(c+=12):12===c&&(c=0)),i.date.hours(c),z.showPicker.call(i)},selectMinute:function(b){i.date.minutes(parseInt(a(b.target).text(),10)),z.showPicker.call(i)},selectSecond:function(b){i.date.seconds(parseInt(a(b.target).text(),10)),z.showPicker.call(i)}},A=function(c){var d=b(i.date),e=a(c.currentTarget).data("action"),f=z[e].apply(i,arguments);return B(c),i.date||(i.date=b({y:1970})),K(),x(),o(d,c.type),f},B=function(a){a.stopPropagation(),a.preventDefault()},C=function(a){27===a.keyCode&&i.hide()},D=function(c){b.locale(i.options.language);var d=a(c.target),e=b(i.date),f=b(d.val(),i.format,i.options.useStrict);f.isValid()&&!M(f)&&N(f)?(q(),i.setValue(f),o(e,c.type),K()):(i.viewDate=e,i.unset=!0,o(e,c.type),p(f))},E=function(a){a&&(i.viewMode=Math.max(i.minViewMode,Math.min(2,i.viewMode+a))),i.widget.find(".datepicker > div").hide().filter(".datepicker-"+R.modes[i.viewMode].clsName).show()},F=function(){var b,c,d,e,f;i.widget.on("click",".datepicker *",a.proxy(y,this)),i.widget.on("click","[data-action]",a.proxy(A,this)),i.widget.on("mousedown",a.proxy(B,this)),i.element.on("keydown",a.proxy(C,this)),i.options.pickDate&&i.options.pickTime&&i.widget.on("click.togglePicker",".accordion-toggle",function(g){if(g.stopPropagation(),b=a(this),c=b.closest("ul"),d=c.find(".in"),e=c.find(".collapse:not(.in)"),d&&d.length){if(f=d.data("collapse"),f&&f.transitioning)return;d.collapse("hide"),e.collapse("show"),b.find("span").toggleClass(i.options.icons.time+" "+i.options.icons.date),i.component&&i.component.find("span").toggleClass(i.options.icons.time+" "+i.options.icons.date)}}),i.isInput?i.element.on({click:a.proxy(i.show,this),focus:a.proxy(i.show,this),change:a.proxy(D,this),blur:a.proxy(i.hide,this)}):(i.element.on({change:a.proxy(D,this)},"input"),i.component?(i.component.on("click",a.proxy(i.show,this)),i.component.on("mousedown",a.proxy(B,this))):i.element.on("click",a.proxy(i.show,this)))},G=function(){a(window).on("resize.datetimepicker"+i.id,a.proxy(n,this)),i.isInput||a(document).on("mousedown.datetimepicker"+i.id,a.proxy(i.hide,this))},H=function(){i.widget.off("click",".datepicker *",i.click),i.widget.off("click","[data-action]"),i.widget.off("mousedown",i.stopEvent),i.options.pickDate&&i.options.pickTime&&i.widget.off("click.togglePicker"),i.isInput?i.element.off({focus:i.show,change:D,click:i.show,blur:i.hide}):(i.element.off({change:D},"input"),i.component?(i.component.off("click",i.show),i.component.off("mousedown",i.stopEvent)):i.element.off("click",i.show))},I=function(){a(window).off("resize.datetimepicker"+i.id),i.isInput||a(document).off("mousedown.datetimepicker"+i.id)},J=function(){if(i.element){var b,c=i.element.parents(),d=!1;for(b=0;b0?d:!1},P=function(a){return a=a.toString(),a.length>=2?a:"0"+a},Q=function(){var a='‹›',b='',c='
'+a+'
'+a+b+'
'+a+b+"
",d="";return i.options.pickDate&&i.options.pickTime?(d='
',d+=i.options.sideBySide?'
'+c+'
'+S.getTemplate()+"
":'
    '+c+'
  • '+S.getTemplate()+"
",d+="
"):i.options.pickTime?'":'"},R={modes:[{clsName:"days",navFnc:"month",navStep:1},{clsName:"months",navFnc:"year",navStep:1},{clsName:"years",navFnc:"year",navStep:10}]},S={hourTemplate:'',minuteTemplate:'',secondTemplate:''};S.getTemplate=function(){return'
"+(i.options.useSeconds?'':"")+(i.use24hours?"":'')+" "+(i.options.useSeconds?'":"")+(i.use24hours?"":'')+'"+(i.options.useSeconds?'':"")+(i.use24hours?"":'')+'
'+(i.options.useMinutes?'':"")+"
"+S.hourTemplate+' :'+(i.options.useMinutes?S.minuteTemplate:'00')+":'+S.secondTemplate+"
'+(i.options.useMinutes?'':"")+"
'+(i.options.useSeconds?'
':"")},i.destroy=function(){H(),I(),i.widget.remove(),i.element.removeData("DateTimePicker"),i.component&&i.component.removeData("DateTimePicker")},i.show=function(a){if(!l().prop("disabled")){if(i.options.useCurrent&&""===l().val()){if(1!==i.options.minuteStepping){var c=b(),d=i.options.minuteStepping;c.minutes(Math.round(c.minutes()/d)*d%60).seconds(0),i.setValue(c.format(i.format))}else i.setValue(b().format(i.format));o("",a.type)}a&&"click"===a.type&&i.isInput&&i.widget.hasClass("picker-open")||(i.widget.hasClass("picker-open")?(i.widget.hide(),i.widget.removeClass("picker-open")):(i.widget.show(),i.widget.addClass("picker-open")),i.height=i.component?i.component.outerHeight():i.element.outerHeight(),n(),i.element.trigger({type:"dp.show",date:b(i.date)}),G(),a&&B(a))}},i.disable=function(){var a=l();a.prop("disabled")||(a.prop("disabled",!0),H())},i.enable=function(){var a=l();a.prop("disabled")&&(a.prop("disabled",!1),F())},i.hide=function(){var a,c,d=i.widget.find(".collapse");for(a=0;a1)throw new TypeError("isEnabled expects a single character string parameter");switch(a){case"y":return-1!==g.indexOf("Y");case"M":return-1!==g.indexOf("M");case"d":return-1!==g.toLowerCase().indexOf("d");case"h":case"H":return-1!==g.toLowerCase().indexOf("h");case"m":return-1!==g.indexOf("m");case"s":return-1!==g.indexOf("s");default:return!1}},w=function(){return v("h")||v("m")||v("s")},x=function(){return v("y")||v("M")||v("d")},y=function(){var b=a("").append(a("").append(a("").addClass("prev").attr("data-action","previous").append(a("").addClass(d.icons.previous))).append(a("").addClass("picker-switch").attr("data-action","pickerSwitch").attr("colspan",d.calendarWeeks?"6":"5")).append(a("").addClass("next").attr("data-action","next").append(a("").addClass(d.icons.next)))),c=a("").append(a("").append(a("").attr("colspan",d.calendarWeeks?"8":"7")));return[a("
").addClass("datepicker-days").append(a("").addClass("table-condensed").append(b).append(a(""))),a("
").addClass("datepicker-months").append(a("
").addClass("table-condensed").append(b.clone()).append(c.clone())),a("
").addClass("datepicker-years").append(a("
").addClass("table-condensed").append(b.clone()).append(c.clone()))]},z=function(){var b=a(""),c=a(""),e=a("");return v("h")&&(b.append(a("
").append(a("").attr("href","#").addClass("btn").attr("data-action","incrementHours").append(a("").addClass(d.icons.up)))),c.append(a("").append(a("").addClass("timepicker-hour").attr("data-time-component","hours").attr("data-action","showHours"))),e.append(a("").append(a("").attr("href","#").addClass("btn").attr("data-action","decrementHours").append(a("").addClass(d.icons.down))))),v("m")&&(v("h")&&(b.append(a("").addClass("separator")),c.append(a("").addClass("separator").html(":")),e.append(a("").addClass("separator"))),b.append(a("").append(a("").attr("href","#").addClass("btn").attr("data-action","incrementMinutes").append(a("").addClass(d.icons.up)))),c.append(a("").append(a("").addClass("timepicker-minute").attr("data-time-component","minutes").attr("data-action","showMinutes"))),e.append(a("").append(a("").attr("href","#").addClass("btn").attr("data-action","decrementMinutes").append(a("").addClass(d.icons.down))))),v("s")&&(v("m")&&(b.append(a("").addClass("separator")),c.append(a("").addClass("separator").html(":")),e.append(a("").addClass("separator"))),b.append(a("").append(a("").attr("href","#").addClass("btn").attr("data-action","incrementSeconds").append(a("").addClass(d.icons.up)))),c.append(a("").append(a("").addClass("timepicker-second").attr("data-time-component","seconds").attr("data-action","showSeconds"))),e.append(a("").append(a("").attr("href","#").addClass("btn").attr("data-action","decrementSeconds").append(a("").addClass(d.icons.down))))),f||(b.append(a("").addClass("separator")),c.append(a("").append(a("").addClass("separator"))),a("
").addClass("timepicker-picker").append(a("").addClass("table-condensed").append([b,c,e]))},A=function(){var b=a("
").addClass("timepicker-hours").append(a("
").addClass("table-condensed")),c=a("
").addClass("timepicker-minutes").append(a("
").addClass("table-condensed")),d=a("
").addClass("timepicker-seconds").append(a("
").addClass("table-condensed")),e=[z()];return v("h")&&e.push(b),v("m")&&e.push(c),v("s")&&e.push(d),e},B=function(){var b=[];return d.showTodayButton&&b.push(a("
").append(a("").attr("data-action","today").append(a("").addClass(d.icons.today)))),!d.sideBySide&&x()&&w()&&b.push(a("").append(a("").attr("data-action","togglePicker").append(a("").addClass(d.icons.time)))),d.showClear&&b.push(a("").append(a("").attr("data-action","clear").append(a("").addClass(d.icons.clear)))),a("").addClass("table-condensed").append(a("").append(a("").append(b)))},C=function(){var b=a("
").addClass("bootstrap-datetimepicker-widget dropdown-menu"),c=a("
").addClass("datepicker").append(y()),e=a("
").addClass("timepicker").append(A()),g=a("
    ").addClass("list-unstyled"),h=a("
  • ").addClass("picker-switch"+(d.collapse?" accordion-toggle":"")).append(B());return f&&b.addClass("usetwentyfour"),d.sideBySide&&x()&&w()?(b.addClass("timepicker-sbs"),b.append(a("
    ").addClass("row").append(c.addClass("col-sm-6")).append(e.addClass("col-sm-6"))),b.append(h),b):("top"===d.toolbarPlacement&&g.append(h),x()&&g.append(a("
  • ").addClass(d.collapse&&w()?"collapse in":"").append(c)),"default"===d.toolbarPlacement&&g.append(h),w()&&g.append(a("
  • ").addClass(d.collapse&&x()?"collapse":"").append(e)),"bottom"===d.toolbarPlacement&&g.append(h),b.append(g))},D=function(){var b=c.data(),e={};return b.dateOptions&&b.dateOptions instanceof Object&&(e=a.extend(!0,e,b.dateOptions)),a.each(d,function(a){var c="date"+a.charAt(0).toUpperCase()+a.slice(1);void 0!==b[c]&&(e[a]=b[c])}),e},E=function(){var b,e=(n||c).position(),f=d.widgetPositioning.vertical,g=d.widgetPositioning.horizontal;if(d.widgetParent?b=d.widgetParent.append(o):c.is("input")?b=c.parent().append(o):(b=c,c.children().first().after(o)),"auto"===f&&(f=(n||c).offset().top+o.height()>a(window).height()+a(window).scrollTop()&&o.height()+c.outerHeight()<(n||c).offset().top?"top":"bottom"),"auto"===g&&(g=b.width() div").hide().filter(".datepicker-"+q[i].clsName).show())},H=function(){var b=a("
"),c=l.clone().startOf("w");for(d.calendarWeeks===!0&&b.append(a(""),d.calendarWeeks&&e.append('"),i.push(e)),f="",c.isBefore(l,"M")&&(f+=" old"),c.isAfter(l,"M")&&(f+=" new"),c.isSame(k,"d")&&!m&&(f+=" active"),K(c,"d")||(f+=" disabled"),c.isSame(b(),"d")&&(f+=" today"),(0===c.day()||6===c.day())&&(f+=" weekend"),e.append('"),c.add(1,"d");g.find("tbody").empty().append(i),M(),N()}},P=function(){var b=o.find(".timepicker-hours table"),c=l.clone().startOf("d"),d=[],e=a("");for(l.hour()>11&&!f&&c.hour(12);c.isSame(l,"d")&&(f||l.hour()<12&&c.hour()<12||l.hour()>11);)c.hour()%4===0&&(e=a(""),d.push(e)),e.append('"),c.add(1,"h");b.empty().append(d)},Q=function(){for(var b=o.find(".timepicker-minutes table"),c=l.clone().startOf("h"),e=[],f=a(""),g=1===d.stepping?5:d.stepping;l.isSame(c,"h");)c.minute()%(4*g)===0&&(f=a(""),e.push(f)),f.append('"),c.add(g,"m");b.empty().append(e)},R=function(){for(var b=o.find(".timepicker-seconds table"),c=l.clone().startOf("m"),d=[],e=a("");l.isSame(c,"m");)c.second()%20===0&&(e=a(""),d.push(e)),e.append('"),c.add(5,"s");b.empty().append(d)},S=function(){var a=o.find(".timepicker span[data-time-component]");f||o.find(".timepicker [data-action=togglePeriod]").text(k.format("A")),a.filter("[data-time-component=hours]").text(k.format(f?"HH":"hh")),a.filter("[data-time-component=minutes]").text(k.format("mm")),a.filter("[data-time-component=seconds]").text(k.format("ss")),P(),Q(),R()},T=function(){o&&(O(),S())},U=function(a){var b=m?null:k;return a?(a=a.clone().locale(d.locale),1!==d.stepping&&a.minutes(Math.round(a.minutes()/d.stepping)*d.stepping%60).seconds(0),void(K(a)?(k=a,l=k.clone(),e.val(k.format(g)),c.data("date",k.format(g)),T(),m=!1,F({type:"dp.change",date:k.clone(),oldDate:b})):(e.val(m?"":k.format(g)),F({type:"dp.error",date:a})))):(m=!0,e.val(""),c.data("date",""),F({type:"dp.change",date:null,oldDate:b}),void T())},V=function(){var b=!1;return o?(o.find(".collapse").each(function(){var c=a(this).data("collapse");return c&&c.transitioning?(b=!0,!1):void 0}),b?j:(n&&n.hasClass("btn")&&n.toggleClass("active"),o.hide(),a(window).off("resize",E),o.off("click","[data-action]"),o.off("mousedown",!1),o.remove(),o=!1,F({type:"dp.hide",date:k.clone()}),j)):j},W={next:function(){l.add(q[i].navStep,q[i].navFnc),O()},previous:function(){l.subtract(q[i].navStep,q[i].navFnc),O()},pickerSwitch:function(){G(1)},selectMonth:function(b){var c=a(b.target).closest("tbody").find("span").index(a(b.target));l.month(c),i===p&&(U(k.clone().year(l.year()).month(l.month())),V()),G(-1),O()},selectYear:function(b){var c=parseInt(a(b.target).text(),10)||0;l.year(c),i===p&&(U(k.clone().year(l.year())),V()),G(-1),O()},selectDay:function(b){var c=l.clone();a(b.target).is(".old")&&c.subtract(1,"M"),a(b.target).is(".new")&&c.add(1,"M"),U(c.date(parseInt(a(b.target).text(),10))),w()||d.keepOpen||V()},incrementHours:function(){U(k.clone().add(1,"h"))},incrementMinutes:function(){U(k.clone().add(d.stepping,"m"))},incrementSeconds:function(){U(k.clone().add(1,"s"))},decrementHours:function(){U(k.clone().subtract(1,"h"))},decrementMinutes:function(){U(k.clone().subtract(d.stepping,"m"))},decrementSeconds:function(){U(k.clone().subtract(1,"s"))},togglePeriod:function(){U(k.clone().add(k.hours()>=12?-12:12,"h"))},togglePicker:function(b){var c,e=a(b.target),f=e.closest("ul"),g=f.find(".in"),h=f.find(".collapse:not(.in)");if(g&&g.length){if(c=g.data("collapse"),c&&c.transitioning)return;g.collapse("hide"),h.collapse("show"),e.is("span")?e.toggleClass(d.icons.time+" "+d.icons.date):e.find("span").toggleClass(d.icons.time+" "+d.icons.date)}},showPicker:function(){o.find(".timepicker > div:not(.timepicker-picker)").hide(),o.find(".timepicker .timepicker-picker").show()},showHours:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-hours").show()},showMinutes:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-minutes").show()},showSeconds:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-seconds").show()},selectHour:function(b){var c=parseInt(a(b.target).text(),10);f||(k.hours()>=12?12!==c&&(c+=12):12===c&&(c=0)),U(k.clone().hours(c)),W.showPicker.call(j)},selectMinute:function(b){U(k.clone().minutes(parseInt(a(b.target).text(),10))),W.showPicker.call(j)},selectSecond:function(b){U(k.clone().seconds(parseInt(a(b.target).text(),10))),W.showPicker.call(j)},clear:function(){U(null)},today:function(){U(b())}},X=function(b){return a(b.currentTarget).is(".disabled")?!1:(W[a(b.currentTarget).data("action")].apply(j,arguments),!1)},Y=function(){var c,f={year:function(a){return a.month(0).date(1).hours(0).seconds(0).minutes(0)},month:function(a){return a.date(1).hours(0).seconds(0).minutes(0)},day:function(a){return a.hours(0).seconds(0).minutes(0)},hour:function(a){return a.seconds(0).minutes(0)},minute:function(a){return a.seconds(0)}};return e.prop("disabled")||e.prop("readonly")||o?j:(d.useCurrent&&m&&(c=b(),"string"==typeof d.useCurrent&&(c=f[d.useCurrent](c)),U(c)),o=C(),H(),L(),o.find(".timepicker-hours").hide(),o.find(".timepicker-minutes").hide(),o.find(".timepicker-seconds").hide(),T(),G(),a(window).on("resize",E),o.on("click","[data-action]",X),o.on("mousedown",!1),n&&n.hasClass("btn")&&n.toggleClass("active"),o.show(),E(),e.is(":focus")||e.focus(),F({type:"dp.show"}),j)},Z=function(){return o?V():Y()},$=function(a){return a=b.isMoment(a)||a instanceof Date?b(a):b(a,h,d.useStrict),a.locale(d.locale),a},_=function(a){27===a.keyCode&&V()},ab=function(b){var c=a(b.target).val().trim(),d=c?$(c):null;return U(d),b.stopImmediatePropagation(),!1},bb=function(){e.on({change:ab,blur:V,keydown:_}),c.is("input")?e.on({focus:Y}):n&&(n.on("click",Z),n.on("mousedown",!1))},cb=function(){e.off({change:ab,blur:V,keydown:_}),c.is("input")?e.off({focus:Y}):n&&(n.off("click",Z),n.off("mousedown",!1))},db=function(b){var c={};return a.each(b,function(){var a=$(this);a.isValid()&&(c[a.format("YYYY-MM-DD")]=!0)}),Object.keys(c).length?c:!1},eb=function(){var a=d.format||"L LT";g=a.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(a){return k.localeData().longDateFormat(a)||a}),h=d.extraFormats?d.extraFormats.slice():[],h.indexOf(a)<0&&h.indexOf(g)<0&&h.push(g),f=g.toLowerCase().indexOf("a")<1&&g.indexOf("h")<1,v("y")&&(p=2),v("M")&&(p=1),v("d")&&(p=0),i=Math.max(p,i),m||U(k)};if(j.destroy=function(){V(),cb(),c.removeData("DateTimePicker"),c.removeData("date")},j.toggle=Z,j.show=Y,j.hide=V,j.disable=function(){return V(),n&&n.hasClass("btn")&&n.addClass("disabled"),e.prop("disabled",!0),j},j.enable=function(){return n&&n.hasClass("btn")&&n.removeClass("disabled"),e.prop("disabled",!1),j},j.options=function(b){if(0===arguments.length)return a.extend(!0,{},d);if(!(b instanceof Object))throw new TypeError("options() options parameter should be an object");return a.extend(!0,d,b),a.each(d,function(a,b){if(void 0===j[a])throw new TypeError("option "+a+" is not recognized!");j[a](b)}),j},j.date=function(a){if(0===arguments.length)return m?null:k.clone();if(!(null===a||"string"==typeof a||b.isMoment(a)||a instanceof Date))throw new TypeError("date() parameter must be one of [null, string, moment or Date]");return U(null===a?null:$(a)),j},j.format=function(a){if(0===arguments.length)return d.format;if("string"!=typeof a&&("boolean"!=typeof a||a!==!1))throw new TypeError("format() expects a sting or boolean:false parameter "+a);return d.format=a,g&&eb(),j},j.dayViewHeaderFormat=function(a){if(0===arguments.length)return d.dayViewHeaderFormat;if("string"!=typeof a)throw new TypeError("dayViewHeaderFormat() expects a string parameter");return d.dayViewHeaderFormat=a,j},j.extraFormats=function(a){if(0===arguments.length)return d.extraFormats;if(a!==!1&&!(a instanceof Array))throw new TypeError("extraFormats() expects an array or false parameter");return d.extraFormats=a,h&&eb(),j},j.disabledDates=function(b){if(0===arguments.length)return d.disabledDates?a.extend({},d.disabledDates):d.disabledDates;if(!b)return d.disabledDates=!1,T(),j;if(!(b instanceof Array))throw new TypeError("disabledDates() expects an array parameter");return d.disabledDates=db(b),d.enabledDates=!1,T(),j},j.enabledDates=function(b){if(0===arguments.length)return d.enabledDates?a.extend({},d.enabledDates):d.enabledDates;if(!b)return d.enabledDates=!1,T(),j;if(!(b instanceof Array))throw new TypeError("enabledDates() expects an array parameter");return d.enabledDates=db(b),d.disabledDates=!1,T(),j},j.daysOfWeekDisabled=function(a){if(0===arguments.length)return d.daysOfWeekDisabled.splice(0);if(!(a instanceof Array))throw new TypeError("daysOfWeekDisabled() expects an array parameter");return d.daysOfWeekDisabled=a.reduce(function(a,b){return b=parseInt(b,10),b>6||0>b||isNaN(b)?a:(-1===a.indexOf(b)&&a.push(b),a)},[]).sort(),T(),j},j.maxDate=function(a){if(0===arguments.length)return d.maxDate?d.maxDate.clone():d.maxDate;if("boolean"==typeof a&&a===!1)return d.maxDate=!1,T(),j;var b=$(a);if(!b.isValid())throw new TypeError("maxDate() Could not parse date parameter: "+a);if(d.minDate&&b.isBefore(d.minDate))throw new TypeError("maxDate() date parameter is before options.minDate: "+b.format(g));return d.maxDate=b,d.maxDate.isBefore(a)&&U(d.maxDate),T(),j},j.minDate=function(a){if(0===arguments.length)return d.minDate?d.minDate.clone():d.minDate;if("boolean"==typeof a&&a===!1)return d.minDate=!1,T(),j;var b=$(a);if(!b.isValid())throw new TypeError("minDate() Could not parse date parameter: "+a);if(d.maxDate&&b.isAfter(d.maxDate))throw new TypeError("minDate() date parameter is after options.maxDate: "+b.format(g));return d.minDate=b,d.minDate.isAfter(a)&&U(d.minDate),T(),j},j.defaultDate=function(a){if(0===arguments.length)return d.defaultDate?d.defaultDate.clone():d.defaultDate;if(!a)return d.defaultDate=!1,j;var b=$(a);if(!b.isValid())throw new TypeError("defaultDate() Could not parse date parameter: "+a);if(!K(b))throw new TypeError("defaultDate() date passed is invalid according to component setup validations");return d.defaultDate=b,d.defaultDate&&""===e.val().trim()&&U(d.defaultDate),j},j.locale=function(a){if(0===arguments.length)return d.locale;if(!b.localeData(a))throw new TypeError("locale() locale "+a+" is not loaded from moment locales!");return d.locale=a,k.locale(d.locale),l.locale(d.locale),g&&eb(),o&&(V(),Y()),j},j.stepping=function(a){return 0===arguments.length?d.stepping:(a=parseInt(a,10),(isNaN(a)||1>a)&&(a=1),d.stepping=a,j)},j.useCurrent=function(a){var b=["year","month","day","hour","minute"];if(0===arguments.length)return d.useCurrent;if("boolean"!=typeof a&&"string"!=typeof a)throw new TypeError("useCurrent() expects a boolean or string parameter");if("string"==typeof a&&-1===b.indexOf(a.toLowerCase()))throw new TypeError("useCurrent() expects a string parameter of "+b.join(", "));return d.useCurrent=a,j},j.collapse=function(a){if(0===arguments.length)return d.collapse;if("boolean"!=typeof a)throw new TypeError("collapse() expects a boolean parameter");return d.collapse===a?j:(d.collapse=a,o&&(V(),Y()),j)},j.icons=function(b){if(0===arguments.length)return a.extend({},d.icons);if(!(b instanceof Object))throw new TypeError("icons() expects parameter to be an Object");return a.extend(d.icons,b),o&&(V(),Y()),j},j.useStrict=function(a){if(0===arguments.length)return d.useStrict;if("boolean"!=typeof a)throw new TypeError("useStrict() expects a boolean parameter");return d.useStrict=a,j},j.sideBySide=function(a){if(0===arguments.length)return d.sideBySide;if("boolean"!=typeof a)throw new TypeError("sideBySide() expects a boolean parameter");return d.sideBySide=a,o&&(V(),Y()),j},j.viewMode=function(a){if(0===arguments.length)return d.viewMode;if("string"!=typeof a)throw new TypeError("viewMode() expects a string parameter");if(-1===r.indexOf(a))throw new TypeError("viewMode() parameter must be one of ("+r.join(", ")+") value");return d.viewMode=a,i=Math.max(r.indexOf(a),p),G(),j},j.toolbarPlacement=function(a){if(0===arguments.length)return d.toolbarPlacement;if("string"!=typeof a)throw new TypeError("toolbarPlacement() expects a string parameter");if(-1===u.indexOf(a))throw new TypeError("toolbarPlacement() parameter must be one of ("+u.join(", ")+") value");return d.toolbarPlacement=a,o&&(V(),Y()),j},j.widgetPositioning=function(b){if(0===arguments.length)return a.extend({},d.widgetPositioning);if("[object Object]"!=={}.toString.call(b))throw new TypeError("widgetPositioning() expects an object variable");if(b.horizontal){if("string"!=typeof b.horizontal)throw new TypeError("widgetPositioning() horizontal variable must be a string");if(b.horizontal=b.horizontal.toLowerCase(),-1===t.indexOf(b.horizontal))throw new TypeError("widgetPositioning() expects horizontal parameter to be one of ("+t.join(", ")+")");d.widgetPositioning.horizontal=b.horizontal}if(b.vertical){if("string"!=typeof b.vertical)throw new TypeError("widgetPositioning() vertical variable must be a string");if(b.vertical=b.vertical.toLowerCase(),-1===s.indexOf(b.vertical))throw new TypeError("widgetPositioning() expects vertical parameter to be one of ("+s.join(", ")+")");d.widgetPositioning.vertical=b.vertical}return T(),j},j.calendarWeeks=function(a){if(0===arguments.length)return d.calendarWeeks;if("boolean"!=typeof a)throw new TypeError("calendarWeeks() expects parameter to be a boolean value");return d.calendarWeeks=a,T(),j},j.showTodayButton=function(a){if(0===arguments.length)return d.showTodayButton;if("boolean"!=typeof a)throw new TypeError("showTodayButton() expects a boolean parameter");return d.showTodayButton=a,o&&(V(),Y()),j},j.showClear=function(a){if(0===arguments.length)return d.showClear;if("boolean"!=typeof a)throw new TypeError("showClear() expects a boolean parameter");return d.showClear=a,o&&(V(),Y()),j},j.widgetParent=function(b){if(0===arguments.length)return d.widgetParent;if("string"==typeof b&&(b=a(b)),null!==b&&"string"!=typeof b&&!(b instanceof jQuery))throw new TypeError("widgetParent() expects a string or a jQuery object parameter");return d.widgetParent=b,o&&(V(),Y()),j},j.keepOpen=function(a){if(0===arguments.length)return d.format;if("boolean"!=typeof a)throw new TypeError("keepOpen() expects a boolean parameter");return d.keepOpen=a,j},c.is("input"))e=c;else if(e=c.find(".datepickerinput"),0===e.size())e=c.find("input");else if(!e.is("input"))throw new Error('CSS class "datepickerinput" cannot be applied to non input element');if(c.hasClass("input-group")&&(n=c.find(0===c.find(".datepickerbutton").size()?'[class^="input-group-"]':".datepickerbutton")),!e.is("input"))throw new Error("Could not initialize DateTimePicker without an input element");return a.extend(!0,d,D()),j.options(d),eb(),bb(),e.prop("disabled")&&j.disable(),0!==e.val().trim().length?U($(e.val().trim())):d.defaultDate&&U(d.defaultDate),j};a.fn.datetimepicker=function(b){return this.each(function(){var d=a(this);d.data("DateTimePicker")||(b=a.extend(!0,{},a.fn.datetimepicker.defaults,b),d.data("DateTimePicker",c(d,b)))})},a.fn.datetimepicker.defaults={format:!1,dayViewHeaderFormat:"MMMM YYYY",extraFormats:!1,stepping:1,minDate:!1,maxDate:!1,useCurrent:!0,collapse:!0,locale:b.locale(),defaultDate:!1,disabledDates:!1,enabledDates:!1,icons:{time:"glyphicon glyphicon-time",date:"glyphicon glyphicon-calendar",up:"glyphicon glyphicon-chevron-up",down:"glyphicon glyphicon-chevron-down",previous:"glyphicon glyphicon-chevron-left",next:"glyphicon glyphicon-chevron-right",today:"glyphicon glyphicon-screenshot",clear:"glyphicon glyphicon-trash"},useStrict:!1,sideBySide:!1,daysOfWeekDisabled:[],calendarWeeks:!1,viewMode:"days",toolbarPlacement:"default",showTodayButton:!1,showClear:!1,widgetPositioning:{horizontal:"auto",vertical:"auto"},widgetParent:null,keepOpen:!1}}); \ No newline at end of file diff --git a/build/nuget/Bootstrap.v3.Datetimepicker.4.0.0.nupkg b/build/nuget/Bootstrap.v3.Datetimepicker.4.0.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..c53550de88beed037e9f490412753ea1d44255eb GIT binary patch literal 23450 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 literal 0 HcmV?d00001 diff --git a/build/nuget/Bootstrap.v3.Datetimepicker.CSS.4.0.0.nupkg b/build/nuget/Bootstrap.v3.Datetimepicker.CSS.4.0.0.nupkg new file mode 100644 index 0000000000000000000000000000000000000000..d7c3c48ed79af32fc17990aff32aa2896487d98f GIT binary patch literal 24312 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.8.3", - "bootstrap" : ">=3.0", "moment": ">=2.8.0" } } diff --git a/composer.json b/composer.json index cf5646145..642a90340 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "eonasdan/bootstrap-datetimepicker", "type": "component", - "version": "3.1.3", + "version": "4.0.0", "description": "Date/time picker widget based on twitter bootstrap", "keywords": [ "bootstrap", @@ -12,7 +12,6 @@ "require": { "robloach/component-installer": "*", "components/jquery": ">=1.9.1", - "components/bootstrap": "3.*", "moment/moment": ">=2.8" }, "extra": { @@ -23,7 +22,9 @@ "files": [ "build/js/bootstrap-datetimepicker.min.js", "build/css/bootstrap-datetimepicker.css", - "build/css/bootstrap-datetimepicker.min.css" + "build/css/bootstrap-datetimepicker.min.css", + "src/less/_bootstrap-datetimepicker.less", + "src/less/bootstrap-datetimepicker-build.less" ] } } diff --git a/package.json b/package.json index d2cb2e3a8..c84b983e3 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "bootstrap-datetimepicker", - "main": "src/js/bootstrap-datetimepicker.js", - "version": "3.1.3", + "filename": "js/bootstrap-datetimepicker.min.js", + "version": "4.0.0", "repository": { "type": "git", "url": "https://github.com/eonasdan/bootstrap-datetimepicker.git" @@ -18,18 +18,18 @@ "moment" ], "dependencies": { - "moment": "~2.8.1", - "bootstrap": "^3.0", - "jquery": "^1.8.3" + "moment": "~2.8.2", + "bootstrap": "^3.0", + "jquery": "latest" }, "devDependencies": { "grunt": "latest", + "grunt-contrib-jasmine": "^0.7.0", "grunt-contrib-jshint": "latest", + "grunt-contrib-less": "latest", "grunt-contrib-uglify": "latest", "grunt-jscs": "latest", - "load-grunt-tasks": "latest", "grunt-string-replace": "latest", - "grunt-contrib-less": "latest", - "bootstrap": "latest" + "load-grunt-tasks": "latest" } } diff --git a/src/js/bootstrap-datetimepicker.js b/src/js/bootstrap-datetimepicker.js index 44abcc1fe..b912fa8d5 100644 --- a/src/js/bootstrap-datetimepicker.js +++ b/src/js/bootstrap-datetimepicker.js @@ -1,1384 +1,1700 @@ /* -//! version : 3.1.3 -========================================================= -bootstrap-datetimepicker.js -https://github.com/Eonasdan/bootstrap-datetimepicker -========================================================= -The MIT License (MIT) - -Copyright (c) 2014 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 -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. -*/ -;(function (root, factory) { + //! version : 4.0.0 + ========================================================= + bootstrap-datetimejs + https://github.com/Eonasdan/bootstrap-datetimepicker + ========================================================= + The MIT License (MIT) + + 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 + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. + */ +(function (factory) { 'use strict'; if (typeof define === 'function' && define.amd) { // AMD is used - Register as an anonymous module. define(['jquery', 'moment'], factory); } else if (typeof exports === 'object') { factory(require('jquery'), require('moment')); - } - else { - // Neither AMD or CommonJS used. Use global variables. + } else { + // Neither AMD nor CommonJS used. Use global variables. if (!jQuery) { - throw new Error('bootstrap-datetimepicker requires jQuery to be loaded first'); + throw 'bootstrap-datetimepicker requires jQuery to be loaded first'; } if (!moment) { - throw new Error('bootstrap-datetimepicker requires moment.js to be loaded first'); + throw 'bootstrap-datetimepicker requires Moment.js to be loaded first'; } - factory(root.jQuery, moment); + factory(jQuery, moment); } -}(this, function ($, moment) { +}(function ($, moment) { 'use strict'; - if (typeof moment === 'undefined') { - throw new Error('momentjs is required'); + if (!moment) { + throw new Error('bootstrap-datetimepicker requires Moment.js to be loaded first'); } - var dpgId = 0, + var dateTimePicker = function (element, options) { + 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': + return actualFormat.indexOf('M') !== -1; + case 'd': + return actualFormat.toLowerCase().indexOf('d') !== -1; + case 'h': + case 'H': + return actualFormat.toLowerCase().indexOf('h') !== -1; + case 'm': + return actualFormat.indexOf('m') !== -1; + case 's': + return actualFormat.indexOf('s') !== -1; + default: + return false; + } + }, - DateTimePicker = function (element, options) { - var defaults = $.fn.datetimepicker.defaults, + hasTime = function () { + return (isEnabled('h') || isEnabled('m') || isEnabled('s')); + }, - icons = { - time: 'glyphicon glyphicon-time', - date: 'glyphicon glyphicon-calendar', - up: 'glyphicon glyphicon-chevron-up', - down: 'glyphicon glyphicon-chevron-down' + hasDate = function () { + return (isEnabled('y') || isEnabled('M') || isEnabled('d')); }, - picker = this, - errored = false, - dDate, + getDatePickerTemplate = function () { + var headTemplate = $('') + .append($('') + .append($('') + .append($('') + .append($('
").addClass("cw").text("#"));c.isBefore(l.clone().endOf("w"));)b.append(a("").addClass("dow").text(c.format("dd"))),c.add(1,"d");o.find(".datepicker-days thead").append(b)},I=function(a){return d.disabledDates?d.disabledDates[a.format("YYYY-MM-DD")]===!0:!1},J=function(a){return d.enabledDates?d.enabledDates[a.format("YYYY-MM-DD")]===!0:!1},K=function(a,b){return a.isValid()?d.disabledDates&&I(a)?!1:d.enabledDates&&J(a)?!0:d.minDate&&a.isBefore(d.minDate,b)?!1:d.maxDate&&a.isAfter(d.maxDate,b)?!1:"d"===b&&-1!==d.daysOfWeekDisabled.indexOf(a.day())?!1:!0:!1},L=function(){for(var b=[],c=l.clone().startOf("y").hour(12);c.isSame(l,"y");)b.push(a("").attr("data-action","selectMonth").addClass("month").text(c.format("MMM"))),c.add(1,"M");o.find(".datepicker-months td").empty().append(b)},M=function(){var b=o.find(".datepicker-months"),c=b.find("th"),d=b.find("tbody").find("span");b.find(".disabled").removeClass("disabled"),K(l.clone().subtract(1,"y"),"y")||c.eq(0).addClass("disabled"),c.eq(1).text(l.year()),K(l.clone().add(1,"y"),"y")||c.eq(2).addClass("disabled"),d.removeClass("active"),k.isSame(l,"y")&&d.eq(k.month()).addClass("active"),d.each(function(b){K(l.clone().month(b),"M")||a(this).addClass("disabled")})},N=function(){var a=o.find(".datepicker-years"),b=a.find("th"),c=l.clone().subtract(5,"y"),e=l.clone().add(6,"y"),f="";for(a.find(".disabled").removeClass("disabled"),d.minDate&&d.minDate.isAfter(c,"y")&&b.eq(0).addClass("disabled"),b.eq(1).text(c.year()+"-"+e.year()),d.maxDate&&d.maxDate.isBefore(e,"y")&&b.eq(2).addClass("disabled");!c.isAfter(e,"y");)f+=''+c.year()+"",c.add(1,"y");a.find("td").html(f)},O=function(){var c,e,f,g=o.find(".datepicker-days"),h=g.find("th"),i=[];if(x()){for(g.find(".disabled").removeClass("disabled"),h.eq(1).text(l.format(d.dayViewHeaderFormat)),K(l.clone().subtract(1,"M"),"M")||h.eq(0).addClass("disabled"),K(l.clone().add(1,"M"),"M")||h.eq(2).addClass("disabled"),c=l.clone().startOf("M").startOf("week");!l.clone().endOf("M").endOf("w").isBefore(c,"d");)0===c.weekday()&&(e=a("
'+c.week()+"'+c.date()+"
'+c.format(f?"HH":"hh")+"
'+c.format("mm")+"
'+c.format("ss")+"
').addClass('prev').attr('data-action', 'previous') + .append($('').addClass(options.icons.previous)) + ) + .append($('').addClass('picker-switch').attr('data-action', 'pickerSwitch').attr('colspan', (options.calendarWeeks ? '6' : '5'))) + .append($('').addClass('next').attr('data-action', 'next') + .append($('').addClass(options.icons.next)) + ) + ), + contTemplate = $('
').attr('colspan', (options.calendarWeeks ? '8' : '7'))) + ); + + return [ + $('
').addClass('datepicker-days') + .append($('').addClass('table-condensed') + .append(headTemplate) + .append($('')) + ), + $('
').addClass('datepicker-months') + .append($('
').addClass('table-condensed') + .append(headTemplate.clone()) + .append(contTemplate.clone()) + ), + $('
').addClass('datepicker-years') + .append($('
').addClass('table-condensed') + .append(headTemplate.clone()) + .append(contTemplate.clone()) + ) + ]; + }, + + getTimePickerMainTemplate = function () { + var topRow = $(''), + middleRow = $(''), + bottomRow = $(''); + + if (isEnabled('h')) { + topRow.append($('
') + .append($('').attr('href', '#').addClass('btn').attr('data-action', 'incrementHours') + .append($('').addClass(options.icons.up)))); + middleRow.append($('') + .append($('').addClass('timepicker-hour').attr('data-time-component', 'hours').attr('data-action', 'showHours'))); + bottomRow.append($('') + .append($('').attr('href', '#').addClass('btn').attr('data-action', 'decrementHours') + .append($('').addClass(options.icons.down)))); + } + if (isEnabled('m')) { + if (isEnabled('h')) { + topRow.append($('').addClass('separator')); + middleRow.append($('').addClass('separator').html(':')); + bottomRow.append($('').addClass('separator')); + } + topRow.append($('') + .append($('').attr('href', '#').addClass('btn').attr('data-action', 'incrementMinutes') + .append($('').addClass(options.icons.up)))); + middleRow.append($('') + .append($('').addClass('timepicker-minute').attr('data-time-component', 'minutes').attr('data-action', 'showMinutes'))); + bottomRow.append($('') + .append($('').attr('href', '#').addClass('btn').attr('data-action', 'decrementMinutes') + .append($('').addClass(options.icons.down)))); + } + if (isEnabled('s')) { + if (isEnabled('m')) { + topRow.append($('').addClass('separator')); + middleRow.append($('').addClass('separator').html(':')); + bottomRow.append($('').addClass('separator')); + } + topRow.append($('') + .append($('').attr('href', '#').addClass('btn').attr('data-action', 'incrementSeconds') + .append($('').addClass(options.icons.up)))); + middleRow.append($('') + .append($('').addClass('timepicker-second').attr('data-time-component', 'seconds').attr('data-action', 'showSeconds'))); + bottomRow.append($('') + .append($('').attr('href', '#').addClass('btn').attr('data-action', 'decrementSeconds') + .append($('').addClass(options.icons.down)))); + } + + if (!use24Hours) { + topRow.append($('').addClass('separator')); + middleRow.append($('') + .append($('').addClass('separator')); + } - init = function () { - var icon = false, localeData, rInterval; - picker.options = $.extend({}, defaults, options); - picker.options.icons = $.extend({}, icons, picker.options.icons); + return $('
').addClass('timepicker-picker') + .append($('').addClass('table-condensed') + .append([topRow, middleRow, bottomRow])); + }, - picker.element = $(element); + getTimePickerTemplate = function () { + var hoursView = $('
').addClass('timepicker-hours') + .append($('
').addClass('table-condensed')), + minutesView = $('
').addClass('timepicker-minutes') + .append($('
').addClass('table-condensed')), + secondsView = $('
').addClass('timepicker-seconds') + .append($('
').addClass('table-condensed')), + ret = [getTimePickerMainTemplate()]; + + if (isEnabled('h')) { + ret.push(hoursView); + } + if (isEnabled('m')) { + ret.push(minutesView); + } + if (isEnabled('s')) { + ret.push(secondsView); + } - dataToOptions(); + return ret; + }, - if (!(picker.options.pickTime || picker.options.pickDate)) { - throw new Error('Must choose at least one picker'); - } + getToolbar = function () { + var row = []; + if (options.showTodayButton) { + row.push($('
').append($('').attr('data-action', 'today').append($('').addClass(options.icons.today)))); + } + if (!options.sideBySide && hasDate() && hasTime()) { + row.push($('').append($('').attr('data-action', 'togglePicker').append($('').addClass(options.icons.time)))); + } + if (options.showClear) { + row.push($('').append($('').attr('data-action', 'clear').append($('').addClass(options.icons.clear)))); + } + return $('').addClass('table-condensed').append($('').append($('').append(row))); + }, - picker.id = dpgId++; - moment.locale(picker.options.language); - picker.date = moment(); - picker.unset = false; - picker.isInput = picker.element.is('input'); - picker.component = false; + getTemplate = function () { + var template = $('
').addClass('bootstrap-datetimepicker-widget dropdown-menu'), + dateView = $('
').addClass('datepicker').append(getDatePickerTemplate()), + timeView = $('
').addClass('timepicker').append(getTimePickerTemplate()), + content = $('
    ').addClass('list-unstyled'), + toolbar = $('
  • ').addClass('picker-switch' + (options.collapse ? ' accordion-toggle' : '')).append(getToolbar()); - if (picker.element.hasClass('input-group')) { - if (picker.element.find('.datepickerbutton').size() === 0) {//in case there is more then one 'input-group-addon' Issue #48 - picker.component = picker.element.find('[class^="input-group-"]'); + if (use24Hours) { + template.addClass('usetwentyfour'); } - else { - picker.component = picker.element.find('.datepickerbutton'); + if (options.sideBySide && hasDate() && hasTime()) { + template.addClass('timepicker-sbs'); + template.append( + $('
    ').addClass('row') + .append(dateView.addClass('col-sm-6')) + .append(timeView.addClass('col-sm-6')) + ); + template.append(toolbar); + return template; } - } - picker.format = picker.options.format; - localeData = moment().localeData(); + if (options.toolbarPlacement === 'top') { + content.append(toolbar); + } + if (hasDate()) { + content.append($('
  • ').addClass((options.collapse && hasTime() ? 'collapse in' : '')).append(dateView)); + } + if (options.toolbarPlacement === 'default') { + content.append(toolbar); + } + if (hasTime()) { + content.append($('
  • ').addClass((options.collapse && hasDate() ? 'collapse' : '')).append(timeView)); + } + if (options.toolbarPlacement === 'bottom') { + content.append(toolbar); + } + return template.append(content); + }, + + dataToOptions = function () { + var eData = element.data(), + dataOptions = {}; - if (!picker.format) { - picker.format = (picker.options.pickDate ? localeData.longDateFormat('L') : ''); - if (picker.options.pickDate && picker.options.pickTime) { - picker.format += ' '; + if (eData.dateOptions && eData.dateOptions instanceof Object) { + dataOptions = $.extend(true, dataOptions, eData.dateOptions); } - picker.format += (picker.options.pickTime ? localeData.longDateFormat('LT') : ''); - if (picker.options.useSeconds) { - if (localeData.longDateFormat('LT').indexOf(' A') !== -1) { - picker.format = picker.format.split(' A')[0] + ':ss A'; + + $.each(options, function (key) { + var attributeName = 'date' + key.charAt(0).toUpperCase() + key.slice(1); + if (eData[attributeName] !== undefined) { + dataOptions[key] = eData[attributeName]; } - else { - picker.format += ':ss'; + }); + 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); + } + + // 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'; } } - } - picker.use24hours = (picker.format.toLowerCase().indexOf('a') < 0 && picker.format.indexOf('h') < 0); - if (picker.component) { - icon = picker.component.find('span'); - } + // Left and right logic + if (horizontal === 'auto') { + if (parent.width() < offset.left + widget.outerWidth()) { + horizontal = 'right'; + } else { + horizontal = 'left'; + } + } - if (picker.options.pickTime) { - if (icon) { - icon.addClass(picker.options.icons.time); + if (vertical === 'top') { + widget.addClass('top').removeClass('bottom'); + } else { + widget.addClass('bottom').removeClass('top'); } - } - if (picker.options.pickDate) { - if (icon) { - icon.removeClass(picker.options.icons.time); - icon.addClass(picker.options.icons.date); + + if (horizontal === 'right') { + widget.addClass('pull-right'); + } else { + widget.removeClass('pull-right'); } - } - picker.options.widgetParent = - typeof picker.options.widgetParent === 'string' && picker.options.widgetParent || - picker.element.parents().filter(function () { - return 'scroll' === $(this).css('overflow-y'); - }).get(0) || - 'body'; + // 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(); + } - picker.widget = $(getTemplate()).appendTo(picker.options.widgetParent); + if (parent.length === 0) { + throw new Error('datetimepicker component should be placed within a relative positioned container'); + } - picker.minViewMode = picker.options.minViewMode || 0; - if (typeof picker.minViewMode === 'string') { - switch (picker.minViewMode) { - case 'months': - picker.minViewMode = 1; - break; - case 'years': - picker.minViewMode = 2; - break; - default: - picker.minViewMode = 0; - break; - } - } - picker.viewMode = picker.options.viewMode || 0; - if (typeof picker.viewMode === 'string') { - switch (picker.viewMode) { - case 'months': - picker.viewMode = 1; - break; - case 'years': - picker.viewMode = 2; - break; - default: - picker.viewMode = 0; - break; + 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') + }); + }, + + notifyEvent = function (e) { + if (e.type === 'dp.change' && ((e.date && e.date.isSame(e.oldDate)) || (!e.date && !e.oldDate))) { + return; } - } + element.trigger(e); + }, - picker.viewMode = Math.max(picker.viewMode, picker.minViewMode); + 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(); + }, - picker.options.disabledDates = indexGivenDates(picker.options.disabledDates); - picker.options.enabledDates = indexGivenDates(picker.options.enabledDates); + fillDow = function () { + var row = $('
'), + currentDate = viewDate.clone().startOf('w'); - picker.startViewMode = picker.viewMode; - picker.setMinDate(picker.options.minDate); - picker.setMaxDate(picker.options.maxDate); - fillDow(); - fillMonths(); - fillHours(); - fillMinutes(); - fillSeconds(); - update(); - showMode(); - if (!getPickerInput().prop('disabled')) { - attachDatePickerEvents(); - } - if (picker.options.defaultDate !== '' && getPickerInput().val() === '') { - picker.setValue(picker.options.defaultDate); - } - if (picker.options.minuteStepping !== 1) { - rInterval = picker.options.minuteStepping; - picker.date.minutes((Math.round(picker.date.minutes() / rInterval) * rInterval) % 60).seconds(0); - } - }, + if (options.calendarWeeks === true) { + row.append($(''), weekdaysMin = moment.weekdaysMin(), i; - if (picker.options.calendarWeeks === true) { - html.append(''); - } - if (moment().localeData()._week.dow === 0) { // starts on Sunday - for (i = 0; i < 7; i++) { - html.append(''); + yearsView.find('td').html(html); + }, + + fillDate = function () { + var daysView = widget.find('.datepicker-days'), + daysViewHeader = daysView.find('th'), + currentDate, + html = [], + row, + clsName; + + if (!hasDate()) { + return; } - } else { - for (i = 1; i < 8; i++) { - if (i === 7) { - html.append(''); - } else { - html.append(''); + + daysView.find('.disabled').removeClass('disabled'); + daysViewHeader.eq(1).text(viewDate.format(options.dayViewHeaderFormat)); + + 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'); + } + + currentDate = viewDate.clone().startOf('M').startOf('week'); + + while (!viewDate.clone().endOf('M').endOf('w').isBefore(currentDate, 'd')) { + if (currentDate.weekday() === 0) { + row = $(''); + if (options.calendarWeeks) { + row.append(''); + } + 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'; + } + if (currentDate.day() === 0 || currentDate.day() === 6) { + clsName += ' weekend'; } + row.append(''); + currentDate.add(1, 'd'); } - } - picker.widget.find('.datepicker-days thead').append(html); - }, - fillMonths = function () { - moment.locale(picker.options.language); - var html = '', i, monthsShort = moment.monthsShort(); - for (i = 0; i < 12; i++) { - html += '' + monthsShort[i] + ''; - } - picker.widget.find('.datepicker-months td').append(html); - }, + daysView.find('tbody').empty().append(html); - fillDate = function () { - if (!picker.options.pickDate) { - return; - } - moment.locale(picker.options.language); - var year = picker.viewDate.year(), - month = picker.viewDate.month(), - startYear = picker.options.minDate.year(), - startMonth = picker.options.minDate.month(), - endYear = picker.options.maxDate.year(), - endMonth = picker.options.maxDate.month(), - currentDate, - prevMonth, nextMonth, html = [], row, clsName, i, days, yearCont, currentYear, months = moment.months(); + updateMonths(); - picker.widget.find('.datepicker-days').find('.disabled').removeClass('disabled'); - picker.widget.find('.datepicker-months').find('.disabled').removeClass('disabled'); - picker.widget.find('.datepicker-years').find('.disabled').removeClass('disabled'); + updateYears(); + }, - picker.widget.find('.datepicker-days th:eq(1)').text( - months[month] + ' ' + year); + fillHours = function () { + var table = widget.find('.timepicker-hours table'), + currentHour = viewDate.clone().startOf('d'), + html = [], + row = $(''); - prevMonth = moment(picker.viewDate, picker.format, picker.options.useStrict).subtract(1, 'months'); - days = prevMonth.daysInMonth(); - prevMonth.date(days).startOf('week'); - if ((year === startYear && month <= startMonth) || year < startYear) { - picker.widget.find('.datepicker-days th:eq(0)').addClass('disabled'); - } - if ((year === endYear && month >= endMonth) || year > endYear) { - picker.widget.find('.datepicker-days th:eq(2)').addClass('disabled'); - } + 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 = $(''); + html.push(row); + } + row.append(''); + currentHour.add(1, 'h'); + } + table.empty().append(html); + }, - nextMonth = moment(prevMonth).add(42, 'd'); - while (prevMonth.isBefore(nextMonth)) { - if (prevMonth.weekday() === moment().startOf('week').weekday()) { + 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 = $(''); + html.push(row); + } + row.append(''); + currentMinute.add(step, 'm'); + } + table.empty().append(html); + }, + + fillSeconds = function () { + var table = widget.find('.timepicker-seconds table'), + currentSecond = viewDate.clone().startOf('m'), + html = [], row = $(''); - html.push(row); - if (picker.options.calendarWeeks === true) { - row.append(''); + + while (viewDate.isSame(currentSecond, 'm')) { + if (currentSecond.second() % 20 === 0) { + row = $(''); + html.push(row); } + row.append(''); + currentSecond.add(5, 's'); + } + + 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')); } - clsName = ''; - if (prevMonth.year() < year || (prevMonth.year() === year && prevMonth.month() < month)) { - clsName += ' old'; - } else if (prevMonth.year() > year || (prevMonth.year() === year && prevMonth.month() > month)) { - clsName += ' new'; + 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(); + }, + + update = function () { + if (!widget) { + return; } - if (prevMonth.isSame(moment({y: picker.date.year(), M: picker.date.month(), d: picker.date.date()}))) { - clsName += ' active'; + 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; } - if (isInDisableDates(prevMonth, 'day') || !isInEnableDates(prevMonth)) { - clsName += ' disabled'; + + targetMoment = targetMoment.clone().locale(options.locale); + + if (options.stepping !== 1) { + targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping) % 60).seconds(0); } - if (picker.options.showToday === true) { - if (prevMonth.isSame(moment(), 'day')) { - clsName += ' today'; + + 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(); + }, + + 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() && !options.keepOpen) { + 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); + } + + // NOTE: uncomment if toggled state will be restored in show() + //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()); + } + }, + + doAction = function (e) { + if ($(e.currentTarget).is('.disabled')) { + return false; } - if (picker.options.daysOfWeekDisabled) { - for (i = 0; i < picker.options.daysOfWeekDisabled.length; i++) { - if (prevMonth.day() === picker.options.daysOfWeekDisabled[i]) { - clsName += ' disabled'; - break; + 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 (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); } - row.append(''); - currentDate = prevMonth.date(); - prevMonth.add(1, 'd'); + widget = getTemplate(); + + fillDow(); + fillMonths(); + + widget.find('.timepicker-hours').hide(); + widget.find('.timepicker-minutes').hide(); + widget.find('.timepicker-seconds').hide(); + + update(); + showMode(); + + $(window).on('resize', place); + widget.on('click', '[data-action]', doAction); // this handles clicks on the widget + widget.on('mousedown', false); + + if (component && component.hasClass('btn')) { + component.toggleClass('active'); + } + widget.show(); + place(); + + if (!input.is(':focus')) { + input.focus(); + } + + notifyEvent({ + type: 'dp.show' + }); + return picker; + }, + + toggle = function () { + return (widget ? hide() : show()); + }, + + 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; + }, + + keydown = function (e) { + if (e.keyCode === 27) { // allow escape to hide picker + hide(); + } + }, + + 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 + }); + + 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) 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; + }, + + initFormatting = function () { + var format = options.format || 'L LT'; + + actualFormat = format.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (input) { + return date.localeData().longDateFormat(input) || input; + }); + + parseFormats = options.extraFormats ? options.extraFormats.slice() : []; + if (parseFormats.indexOf(format) < 0 && parseFormats.indexOf(actualFormat) < 0) { + parseFormats.push(actualFormat); + } + + use24Hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.indexOf('h') < 1); + + if (isEnabled('y')) { + minViewModeNumber = 2; + } + if (isEnabled('M')) { + minViewModeNumber = 1; + } + if (isEnabled('d')) { + minViewModeNumber = 0; + } + + currentViewMode = Math.max(minViewModeNumber, currentViewMode); + + if (!unset) { + setValue(date); + } + }; + + /******************************************************************************** + * + * 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'); + }; + + picker.toggle = toggle; + + picker.show = show; + + picker.hide = hide; - if (currentDate === prevMonth.date()) { - prevMonth.add(1, 'd'); - } - } - picker.widget.find('.datepicker-days tbody').empty().append(html); - currentYear = picker.date.year(); - months = picker.widget.find('.datepicker-months').find('th:eq(1)').text(year).end().find('span').removeClass('active'); - if (currentYear === year) { - months.eq(picker.date.month()).addClass('active'); - } - if (year - 1 < startYear) { - picker.widget.find('.datepicker-months th:eq(0)').addClass('disabled'); - } - if (year + 1 > endYear) { - picker.widget.find('.datepicker-months th:eq(2)').addClass('disabled'); - } - for (i = 0; i < 12; i++) { - if ((year === startYear && startMonth > i) || (year < startYear)) { - $(months[i]).addClass('disabled'); - } else if ((year === endYear && endMonth < i) || (year > endYear)) { - $(months[i]).addClass('disabled'); - } + picker.disable = function () { + hide(); + if (component && component.hasClass('btn')) { + component.addClass('disabled'); } + input.prop('disabled', true); + return picker; + }; - html = ''; - year = parseInt(year / 10, 10) * 10; - yearCont = picker.widget.find('.datepicker-years').find( - 'th:eq(1)').text(year + '-' + (year + 9)).parents('table').find('td'); - picker.widget.find('.datepicker-years').find('th').removeClass('disabled'); - if (startYear > year) { - picker.widget.find('.datepicker-years').find('th:eq(0)').addClass('disabled'); - } - if (endYear < year + 9) { - picker.widget.find('.datepicker-years').find('th:eq(2)').addClass('disabled'); + picker.enable = function () { + if (component && component.hasClass('btn')) { + component.removeClass('disabled'); } - year -= 1; - for (i = -1; i < 11; i++) { - html += '' + year + ''; - year += 1; + input.prop('disabled', false); + return picker; + }; + + picker.options = function (newOptions) { + if (arguments.length === 0) { + return $.extend(true, {}, options); } - yearCont.html(html); - }, - fillHours = function () { - moment.locale(picker.options.language); - var table = picker.widget.find('.timepicker .timepicker-hours table'), html = '', current, i, j; - table.parent().hide(); - if (picker.use24hours) { - current = 0; - for (i = 0; i < 6; i += 1) { - html += ''; - for (j = 0; j < 4; j += 1) { - html += ''; - current++; - } - html += ''; - } + if (!(newOptions instanceof Object)) { + throw new TypeError('options() options parameter should be an object'); } - else { - current = 1; - for (i = 0; i < 3; i += 1) { - html += ''; - for (j = 0; j < 4; j += 1) { - html += ''; - current++; - } - html += ''; + $.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!'); } - } - table.html(html); - }, + }); + return picker; + }; - fillMinutes = function () { - var table = picker.widget.find('.timepicker .timepicker-minutes table'), html = '', current = 0, i, j, step = picker.options.minuteStepping; - table.parent().hide(); - if (step === 1) { - step = 5; - } - for (i = 0; i < Math.ceil(60 / step / 4) ; i++) { - html += ''; - for (j = 0; j < 4; j += 1) { - if (current < 60) { - html += ''; - current += step; - } else { - html += ''; - } + picker.date = function (newDate) { + if (arguments.length === 0) { + if (unset) { + return null; } - html += ''; + return date.clone(); } - table.html(html); - }, - fillSeconds = function () { - var table = picker.widget.find('.timepicker .timepicker-seconds table'), html = '', current = 0, i, j; - table.parent().hide(); - for (i = 0; i < 3; i++) { - html += ''; - for (j = 0; j < 4; j += 1) { - html += ''; - current += 5; - } - html += ''; + if (newDate !== null && typeof newDate !== 'string' && !moment.isMoment(newDate) && !(newDate instanceof Date)) { + throw new TypeError('date() parameter must be one of [null, string, moment or Date]'); } - table.html(html); - }, - fillTime = function () { - if (!picker.date) { - return; + setValue(newDate === null ? null : parseInputDate(newDate)); + return picker; + }; + + picker.format = function (newFormat) { + if (arguments.length === 0) { + return options.format; } - var timeComponents = picker.widget.find('.timepicker span[data-time-component]'), - hour = picker.date.hours(), - period = picker.date.format('A'); - if (!picker.use24hours) { - if (hour === 0) { - hour = 12; - } else if (hour !== 12) { - hour = hour % 12; - } - picker.widget.find('.timepicker [data-action=togglePeriod]').text(period); + + if ((typeof newFormat !== 'string') && ((typeof newFormat !== 'boolean') || (newFormat !== false))) { + throw new TypeError('format() expects a sting or boolean:false parameter ' + newFormat); } - timeComponents.filter('[data-time-component=hours]').text(padLeft(hour)); - timeComponents.filter('[data-time-component=minutes]').text(padLeft(picker.date.minutes())); - timeComponents.filter('[data-time-component=seconds]').text(padLeft(picker.date.second())); - }, - click = function (e) { - e.stopPropagation(); - e.preventDefault(); - picker.unset = false; - var target = $(e.target).closest('span, td, th'), month, year, step, day, oldDate = moment(picker.date); - if (target.length === 1) { - if (!target.is('.disabled')) { - switch (target[0].nodeName.toLowerCase()) { - case 'th': - switch (target[0].className) { - case 'picker-switch': - showMode(1); - break; - case 'prev': - case 'next': - step = dpGlobal.modes[picker.viewMode].navStep; - if (target[0].className === 'prev') { - step = step * -1; - } - picker.viewDate.add(step, dpGlobal.modes[picker.viewMode].navFnc); - fillDate(); - break; - } - break; - case 'span': - if (target.is('.month')) { - month = target.parent().find('span').index(target); - picker.viewDate.month(month); - } else { - year = parseInt(target.text(), 10) || 0; - picker.viewDate.year(year); - } - if (picker.viewMode === picker.minViewMode) { - picker.date = moment({ - y: picker.viewDate.year(), - M: picker.viewDate.month(), - d: picker.viewDate.date(), - h: picker.date.hours(), - m: picker.date.minutes(), - s: picker.date.seconds() - }); - set(); - notifyChange(oldDate, e.type); - } - showMode(-1); - fillDate(); - break; - case 'td': - if (target.is('.day')) { - day = parseInt(target.text(), 10) || 1; - month = picker.viewDate.month(); - year = picker.viewDate.year(); - if (target.is('.old')) { - if (month === 0) { - month = 11; - year -= 1; - } else { - month -= 1; - } - } else if (target.is('.new')) { - if (month === 11) { - month = 0; - year += 1; - } else { - month += 1; - } - } - picker.date = moment({ - y: year, - M: month, - d: day, - h: picker.date.hours(), - m: picker.date.minutes(), - s: picker.date.seconds() - } - ); - picker.viewDate = moment({ - y: year, M: month, d: Math.min(28, day) - }); - fillDate(); - set(); - notifyChange(oldDate, e.type); - } - break; - } - } + options.format = newFormat; + if (actualFormat) { + initFormatting(); // reinit formatting } - }, + return picker; + }; - actions = { - incrementHours: function () { - checkDate('add', 'hours', 1); - }, + picker.dayViewHeaderFormat = function (newFormat) { + if (arguments.length === 0) { + return options.dayViewHeaderFormat; + } - incrementMinutes: function () { - checkDate('add', 'minutes', picker.options.minuteStepping); - }, + if (typeof newFormat !== 'string') { + throw new TypeError('dayViewHeaderFormat() expects a string parameter'); + } - incrementSeconds: function () { - checkDate('add', 'seconds', 1); - }, + options.dayViewHeaderFormat = newFormat; + return picker; + }; - decrementHours: function () { - checkDate('subtract', 'hours', 1); - }, + picker.extraFormats = function (formats) { + if (arguments.length === 0) { + return options.extraFormats; + } - decrementMinutes: function () { - checkDate('subtract', 'minutes', picker.options.minuteStepping); - }, + if (formats !== false && !(formats instanceof Array)) { + throw new TypeError('extraFormats() expects an array or false parameter'); + } - decrementSeconds: function () { - checkDate('subtract', 'seconds', 1); - }, + options.extraFormats = formats; + if (parseFormats) { + initFormatting(); // reinit formatting + } + return picker; + }; - togglePeriod: function () { - var hour = picker.date.hours(); - if (hour >= 12) { - hour -= 12; - } else { - hour += 12; - } - picker.date.hours(hour); - }, + picker.disabledDates = function (dates) { + if (arguments.length === 0) { + return (options.disabledDates ? $.extend({}, options.disabledDates) : options.disabledDates); + } - showPicker: function () { - picker.widget.find('.timepicker > div:not(.timepicker-picker)').hide(); - picker.widget.find('.timepicker .timepicker-picker').show(); - }, + if (!dates) { + options.disabledDates = false; + update(); + return picker; + } + if (!(dates instanceof Array)) { + throw new TypeError('disabledDates() expects an array parameter'); + } + options.disabledDates = indexGivenDates(dates); + options.enabledDates = false; + update(); + return picker; + }; - showHours: function () { - picker.widget.find('.timepicker .timepicker-picker').hide(); - picker.widget.find('.timepicker .timepicker-hours').show(); - }, + picker.enabledDates = function (dates) { + if (arguments.length === 0) { + return (options.enabledDates ? $.extend({}, options.enabledDates) : options.enabledDates); + } - showMinutes: function () { - picker.widget.find('.timepicker .timepicker-picker').hide(); - picker.widget.find('.timepicker .timepicker-minutes').show(); - }, + if (!dates) { + options.enabledDates = false; + update(); + return picker; + } + if (!(dates instanceof Array)) { + throw new TypeError('enabledDates() expects an array parameter'); + } + options.enabledDates = indexGivenDates(dates); + options.disabledDates = false; + update(); + return picker; + }; - showSeconds: function () { - picker.widget.find('.timepicker .timepicker-picker').hide(); - picker.widget.find('.timepicker .timepicker-seconds').show(); - }, + picker.daysOfWeekDisabled = function (daysOfWeekDisabled) { + if (arguments.length === 0) { + return options.daysOfWeekDisabled.splice(0); + } - selectHour: function (e) { - var hour = parseInt($(e.target).text(), 10); - if (!picker.use24hours) { - if (picker.date.hours() >= 12) { - if (hour !== 12) { - hour += 12; - } - } else { - if (hour === 12) { - hour = 0; - } - } + if (!(daysOfWeekDisabled instanceof Array)) { + throw new TypeError('daysOfWeekDisabled() expects an array parameter'); + } + options.daysOfWeekDisabled = daysOfWeekDisabled.reduce(function (previousValue, currentValue) { + currentValue = parseInt(currentValue, 10); + if (currentValue > 6 || currentValue < 0 || isNaN(currentValue)) { + return previousValue; } - picker.date.hours(hour); - actions.showPicker.call(picker); - }, + if (previousValue.indexOf(currentValue) === -1) { + previousValue.push(currentValue); + } + return previousValue; + }, []).sort(); + update(); + return picker; + }; - selectMinute: function (e) { - picker.date.minutes(parseInt($(e.target).text(), 10)); - actions.showPicker.call(picker); - }, + picker.maxDate = function (date) { + if (arguments.length === 0) { + return options.maxDate ? options.maxDate.clone() : options.maxDate; + } - selectSecond: function (e) { - picker.date.seconds(parseInt($(e.target).text(), 10)); - actions.showPicker.call(picker); + if ((typeof date === 'boolean') && date === false) { + options.maxDate = false; + update(); + return picker; } - }, - doAction = function (e) { - var oldDate = moment(picker.date), - action = $(e.currentTarget).data('action'), - rv = actions[action].apply(picker, arguments); - stopEvent(e); - if (!picker.date) { - picker.date = moment({y: 1970}); - } - set(); - fillTime(); - notifyChange(oldDate, e.type); - return rv; - }, + var parsedDate = parseInputDate(date); - stopEvent = function (e) { - e.stopPropagation(); - e.preventDefault(); - }, + if (!parsedDate.isValid()) { + throw new TypeError('maxDate() Could not parse date parameter: ' + date); + } + if (options.minDate && parsedDate.isBefore(options.minDate)) { + throw new TypeError('maxDate() date parameter is before options.minDate: ' + parsedDate.format(actualFormat)); + } + options.maxDate = parsedDate; + if (options.maxDate.isBefore(date)) { + setValue(options.maxDate); + } + update(); + return picker; + }; - keydown = function (e) { - if (e.keyCode === 27) { // allow escape to hide picker - picker.hide(); + picker.minDate = function (date) { + if (arguments.length === 0) { + return options.minDate ? options.minDate.clone() : options.minDate; } - }, - change = function (e) { - moment.locale(picker.options.language); - var input = $(e.target), oldDate = moment(picker.date), newDate = moment(input.val(), picker.format, picker.options.useStrict); - if (newDate.isValid() && !isInDisableDates(newDate) && isInEnableDates(newDate)) { + if ((typeof date === 'boolean') && date === false) { + options.minDate = false; update(); - picker.setValue(newDate); - notifyChange(oldDate, e.type); - set(); + return picker; + } + + var parsedDate = parseInputDate(date); + + if (!parsedDate.isValid()) { + throw new TypeError('minDate() Could not parse date parameter: ' + date); } - else { - picker.viewDate = oldDate; - picker.unset = true; - notifyChange(oldDate, e.type); - notifyError(newDate); + if (options.maxDate && parsedDate.isAfter(options.maxDate)) { + throw new TypeError('minDate() date parameter is after options.maxDate: ' + parsedDate.format(actualFormat)); } - }, + options.minDate = parsedDate; + if (options.minDate.isAfter(date)) { + setValue(options.minDate); + } + update(); + return picker; + }; - showMode = function (dir) { - if (dir) { - picker.viewMode = Math.max(picker.minViewMode, Math.min(2, picker.viewMode + dir)); + picker.defaultDate = function (defaultDate) { + if (arguments.length === 0) { + return options.defaultDate ? options.defaultDate.clone() : options.defaultDate; + } + if (!defaultDate) { + options.defaultDate = false; + return picker; + } + var parsedDate = parseInputDate(defaultDate); + if (!parsedDate.isValid()) { + throw new TypeError('defaultDate() Could not parse date parameter: ' + defaultDate); + } + if (!isValid(parsedDate)) { + throw new TypeError('defaultDate() date passed is invalid according to component setup validations'); } - picker.widget.find('.datepicker > div').hide().filter('.datepicker-' + dpGlobal.modes[picker.viewMode].clsName).show(); - }, - attachDatePickerEvents = function () { - var $this, $parent, expanded, closed, collapseData; - picker.widget.on('click', '.datepicker *', $.proxy(click, this)); // this handles date picker clicks - picker.widget.on('click', '[data-action]', $.proxy(doAction, this)); // this handles time picker clicks - picker.widget.on('mousedown', $.proxy(stopEvent, this)); - picker.element.on('keydown', $.proxy(keydown, this)); - if (picker.options.pickDate && picker.options.pickTime) { - picker.widget.on('click.togglePicker', '.accordion-toggle', function (e) { - e.stopPropagation(); - $this = $(this); - $parent = $this.closest('ul'); - expanded = $parent.find('.in'); - closed = $parent.find('.collapse:not(.in)'); + options.defaultDate = parsedDate; - if (expanded && expanded.length) { - collapseData = expanded.data('collapse'); - if (collapseData && collapseData.transitioning) { - return; - } - expanded.collapse('hide'); - closed.collapse('show'); - $this.find('span').toggleClass(picker.options.icons.time + ' ' + picker.options.icons.date); - if (picker.component) { - picker.component.find('span').toggleClass(picker.options.icons.time + ' ' + picker.options.icons.date); - } - } - }); + if (options.defaultDate && input.val().trim() === '') { + setValue(options.defaultDate); } - if (picker.isInput) { - picker.element.on({ - 'click': $.proxy(picker.show, this), - 'focus': $.proxy(picker.show, this), - 'change': $.proxy(change, this), - 'blur': $.proxy(picker.hide, this) - }); - } else { - picker.element.on({ - 'change': $.proxy(change, this) - }, 'input'); - if (picker.component) { - picker.component.on('click', $.proxy(picker.show, this)); - picker.component.on('mousedown', $.proxy(stopEvent, this)); - } else { - picker.element.on('click', $.proxy(picker.show, this)); - } + return picker; + }; + + picker.locale = function (locale) { + if (arguments.length === 0) { + return options.locale; } - }, - attachDatePickerGlobalEvents = function () { - $(window).on( - 'resize.datetimepicker' + picker.id, $.proxy(place, this)); - if (!picker.isInput) { - $(document).on( - 'mousedown.datetimepicker' + picker.id, $.proxy(picker.hide, this)); + if (!moment.localeData(locale)) { + throw new TypeError('locale() locale ' + locale + ' is not loaded from moment locales!'); } - }, - detachDatePickerEvents = function () { - picker.widget.off('click', '.datepicker *', picker.click); - picker.widget.off('click', '[data-action]'); - picker.widget.off('mousedown', picker.stopEvent); - if (picker.options.pickDate && picker.options.pickTime) { - picker.widget.off('click.togglePicker'); + options.locale = locale; + date.locale(options.locale); + viewDate.locale(options.locale); + + if (actualFormat) { + initFormatting(); // reinit formatting } - if (picker.isInput) { - picker.element.off({ - 'focus': picker.show, - 'change': change, - 'click': picker.show, - 'blur' : picker.hide - }); - } else { - picker.element.off({ - 'change': change - }, 'input'); - if (picker.component) { - picker.component.off('click', picker.show); - picker.component.off('mousedown', picker.stopEvent); - } else { - picker.element.off('click', picker.show); - } + if (widget) { + hide(); + show(); } - }, + return picker; + }; - detachDatePickerGlobalEvents = function () { - $(window).off('resize.datetimepicker' + picker.id); - if (!picker.isInput) { - $(document).off('mousedown.datetimepicker' + picker.id); + picker.stepping = function (stepping) { + if (arguments.length === 0) { + return options.stepping; } - }, - isInFixed = function () { - if (picker.element) { - var parents = picker.element.parents(), inFixed = false, i; - for (i = 0; i < parents.length; i++) { - if ($(parents[i]).css('position') === 'fixed') { - inFixed = true; - break; - } - } - return inFixed; - } else { - return false; + stepping = parseInt(stepping, 10); + if (isNaN(stepping) || stepping < 1) { + stepping = 1; } - }, + options.stepping = stepping; + return picker; + }; - set = function () { - moment.locale(picker.options.language); - var formatted = ''; - if (!picker.unset) { - formatted = moment(picker.date).format(picker.format); - } - getPickerInput().val(formatted); - picker.element.data('date', formatted); - if (!picker.options.pickTime) { - picker.hide(); + picker.useCurrent = function (useCurrent) { + var useCurrentOptions = ['year', 'month', 'day', 'hour', 'minute']; + if (arguments.length === 0) { + return options.useCurrent; } - }, - checkDate = function (direction, unit, amount) { - moment.locale(picker.options.language); - var newDate; - if (direction === 'add') { - newDate = moment(picker.date); - if (newDate.hours() === 23) { - newDate.add(amount, unit); - } - newDate.add(amount, unit); + if ((typeof useCurrent !== 'boolean') && (typeof useCurrent !== 'string')) { + throw new TypeError('useCurrent() expects a boolean or string parameter'); } - else { - newDate = moment(picker.date).subtract(amount, unit); + if (typeof useCurrent === 'string' && useCurrentOptions.indexOf(useCurrent.toLowerCase()) === -1) { + throw new TypeError('useCurrent() expects a string parameter of ' + useCurrentOptions.join(', ')); } - if (isInDisableDates(moment(newDate.subtract(amount, unit))) || isInDisableDates(newDate)) { - notifyError(newDate.format(picker.format)); - return; + options.useCurrent = useCurrent; + return picker; + }; + + picker.collapse = function (collapse) { + if (arguments.length === 0) { + return options.collapse; } - if (direction === 'add') { - picker.date.add(amount, unit); + if (typeof collapse !== 'boolean') { + throw new TypeError('collapse() expects a boolean parameter'); } - else { - picker.date.subtract(amount, unit); + if (options.collapse === collapse) { + return picker; } - picker.unset = false; - }, + options.collapse = collapse; + if (widget) { + hide(); + show(); + } + return picker; + }; - isInDisableDates = function (date, timeUnit) { - moment.locale(picker.options.language); - var maxDate = moment(picker.options.maxDate, picker.format, picker.options.useStrict), - minDate = moment(picker.options.minDate, picker.format, picker.options.useStrict); + picker.icons = function (icons) { + if (arguments.length === 0) { + return $.extend({}, options.icons); + } - if (timeUnit) { - maxDate = maxDate.endOf(timeUnit); - minDate = minDate.startOf(timeUnit); + if (!(icons instanceof Object)) { + throw new TypeError('icons() expects parameter to be an Object'); } + $.extend(options.icons, icons); + if (widget) { + hide(); + show(); + } + return picker; + }; - if (date.isAfter(maxDate) || date.isBefore(minDate)) { - return true; + picker.useStrict = function (useStrict) { + if (arguments.length === 0) { + return options.useStrict; } - if (picker.options.disabledDates === false) { - return false; + + if (typeof useStrict !== 'boolean') { + throw new TypeError('useStrict() expects a boolean parameter'); } - return picker.options.disabledDates[date.format('YYYY-MM-DD')] === true; - }, - isInEnableDates = function (date) { - moment.locale(picker.options.language); - if (picker.options.enabledDates === false) { - return true; + options.useStrict = useStrict; + return picker; + }; + + picker.sideBySide = function (sideBySide) { + if (arguments.length === 0) { + return options.sideBySide; } - return picker.options.enabledDates[date.format('YYYY-MM-DD')] === true; - }, - 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: picker.options.enabledDates['2014-02-27'] === true) - var givenDatesIndexed = {}, givenDatesCount = 0, i; - for (i = 0; i < givenDatesArray.length; i++) { - if (moment.isMoment(givenDatesArray[i]) || givenDatesArray[i] instanceof Date) { - dDate = moment(givenDatesArray[i]); - } else { - dDate = moment(givenDatesArray[i], picker.format, picker.options.useStrict); - } - if (dDate.isValid()) { - givenDatesIndexed[dDate.format('YYYY-MM-DD')] = true; - givenDatesCount++; - } + if (typeof sideBySide !== 'boolean') { + throw new TypeError('sideBySide() expects a boolean parameter'); } - if (givenDatesCount > 0) { - return givenDatesIndexed; + options.sideBySide = sideBySide; + if (widget) { + hide(); + show(); } - return false; - }, + return picker; + }; - padLeft = function (string) { - string = string.toString(); - if (string.length >= 2) { - return string; + picker.viewMode = function (newViewMode) { + if (arguments.length === 0) { + return options.viewMode; } - return '0' + string; - }, - getTemplate = function () { - var - headTemplate = - '' + - '' + - '' + - '' + - '', - contTemplate = - '', - template = '
' + - '
').addClass('cw').text('#')); + } - getPickerInput = function () { - var input; + while (currentDate.isBefore(viewDate.clone().endOf('w'))) { + row.append($('').addClass('dow').text(currentDate.format('dd'))); + currentDate.add(1, 'd'); + } + widget.find('.datepicker-days thead').append(row); + }, - if (picker.isInput) { - return picker.element; - } - input = picker.element.find('.datepickerinput'); - if (input.size() === 0) { - input = picker.element.find('input'); - } - else if (!input.is('input')) { - throw new Error('CSS class "datepickerinput" cannot be applied to non input element'); - } - return input; - }, + isInDisabledDates = function (date) { + if (!options.disabledDates) { + return false; + } + return options.disabledDates[date.format('YYYY-MM-DD')] === true; + }, - dataToOptions = function () { - var eData; - if (picker.element.is('input')) { - eData = picker.element.data(); - } - else { - eData = picker.element.find('input').data(); - } - if (eData.dateFormat !== undefined) { - picker.options.format = eData.dateFormat; - } - if (eData.datePickdate !== undefined) { - picker.options.pickDate = eData.datePickdate; - } - if (eData.datePicktime !== undefined) { - picker.options.pickTime = eData.datePicktime; - } - if (eData.dateUseminutes !== undefined) { - picker.options.useMinutes = eData.dateUseminutes; - } - if (eData.dateUseseconds !== undefined) { - picker.options.useSeconds = eData.dateUseseconds; - } - if (eData.dateUsecurrent !== undefined) { - picker.options.useCurrent = eData.dateUsecurrent; - } - if (eData.calendarWeeks !== undefined) { - picker.options.calendarWeeks = eData.calendarWeeks; - } - if (eData.dateMinutestepping !== undefined) { - picker.options.minuteStepping = eData.dateMinutestepping; - } - if (eData.dateMindate !== undefined) { - picker.options.minDate = eData.dateMindate; - } - if (eData.dateMaxdate !== undefined) { - picker.options.maxDate = eData.dateMaxdate; - } - if (eData.dateShowtoday !== undefined) { - picker.options.showToday = eData.dateShowtoday; - } - if (eData.dateCollapse !== undefined) { - picker.options.collapse = eData.dateCollapse; - } - if (eData.dateLanguage !== undefined) { - picker.options.language = eData.dateLanguage; - } - if (eData.dateDefaultdate !== undefined) { - picker.options.defaultDate = eData.dateDefaultdate; - } - if (eData.dateDisableddates !== undefined) { - picker.options.disabledDates = eData.dateDisableddates; - } - if (eData.dateEnableddates !== undefined) { - picker.options.enabledDates = eData.dateEnableddates; - } - if (eData.dateIcons !== undefined) { - picker.options.icons = eData.dateIcons; - } - if (eData.dateUsestrict !== undefined) { - picker.options.useStrict = eData.dateUsestrict; - } - if (eData.dateDirection !== undefined) { - picker.options.direction = eData.dateDirection; - } - if (eData.dateSidebyside !== undefined) { - picker.options.sideBySide = eData.dateSidebyside; - } - if (eData.dateDaysofweekdisabled !== undefined) { - picker.options.daysOfWeekDisabled = eData.dateDaysofweekdisabled; - } - }, + isInEnabledDates = function (date) { + if (!options.enabledDates) { + return false; + } + return options.enabledDates[date.format('YYYY-MM-DD')] === true; + }, - place = function () { - var position = 'absolute', - offset = picker.component ? picker.component.offset() : picker.element.offset(), - $window = $(window), - placePosition; - - picker.width = picker.component ? picker.component.outerWidth() : picker.element.outerWidth(); - offset.top = offset.top + picker.element.outerHeight(); - - if (picker.options.direction === 'up') { - placePosition = 'top'; - } else if (picker.options.direction === 'bottom') { - placePosition = 'bottom'; - } else if (picker.options.direction === 'auto') { - if (offset.top + picker.widget.height() > $window.height() + $window.scrollTop() && picker.widget.height() + picker.element.outerHeight() < offset.top) { - placePosition = 'top'; - } else { - placePosition = 'bottom'; + isValid = function (targetMoment, granularity) { + if (!targetMoment.isValid()) { + return false; } - } - if (placePosition === 'top') { - offset.bottom = $window.height() - offset.top + picker.element.outerHeight() + 3; - picker.widget.addClass('top').removeClass('bottom'); - } else { - offset.top += 1; - picker.widget.addClass('bottom').removeClass('top'); - } + 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; + }, - if (picker.options.width !== undefined) { - picker.widget.width(picker.options.width); - } + 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($('').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM'))); + monthsShort.add(1, 'M'); + } + widget.find('.datepicker-months td').empty().append(spans); + }, - if (picker.options.orientation === 'left') { - picker.widget.addClass('left-oriented'); - offset.left = offset.left - picker.widget.width() + 20; - } + updateMonths = function () { + var monthsView = widget.find('.datepicker-months'), + monthsViewHeader = monthsView.find('th'), + months = monthsView.find('tbody').find('span'); - if (isInFixed()) { - position = 'fixed'; - offset.top -= $window.scrollTop(); - offset.left -= $window.scrollLeft(); - } + monthsView.find('.disabled').removeClass('disabled'); - if ($window.width() < offset.left + picker.widget.outerWidth()) { - offset.right = $window.width() - offset.left - picker.width; - offset.left = 'auto'; - picker.widget.addClass('pull-right'); - } else { - offset.right = 'auto'; - picker.widget.removeClass('pull-right'); - } + if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) { + monthsViewHeader.eq(0).addClass('disabled'); + } - if (placePosition === 'top') { - picker.widget.css({ - position: position, - bottom: offset.bottom, - top: 'auto', - left: offset.left, - right: offset.right - }); - } else { - picker.widget.css({ - position: position, - top: offset.top, - bottom: 'auto', - left: offset.left, - right: offset.right + monthsViewHeader.eq(1).text(viewDate.year()); + + 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.each(function (index) { + if (!isValid(viewDate.clone().month(index), 'M')) { + $(this).addClass('disabled'); + } }); - } - }, + }, - notifyChange = function (oldDate, eventType) { - if (moment(picker.date).isSame(moment(oldDate)) && !errored) { - return; - } - errored = false; - picker.element.trigger({ - type: 'dp.change', - date: moment(picker.date), - oldDate: moment(oldDate) - }); + 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 = ''; - if (eventType !== 'change') { - picker.element.change(); - } - }, + yearsView.find('.disabled').removeClass('disabled'); - notifyError = function (date) { - errored = true; - picker.element.trigger({ - type: 'dp.error', - date: moment(date, picker.format, picker.options.useStrict) - }); - }, + if (options.minDate && options.minDate.isAfter(startYear, 'y')) { + yearsViewHeader.eq(0).addClass('disabled'); + } + + yearsViewHeader.eq(1).text(startYear.year() + '-' + endYear.year()); - update = function (newDate) { - moment.locale(picker.options.language); - var dateStr = newDate; - if (!dateStr) { - dateStr = getPickerInput().val(); - if (dateStr) { - picker.date = moment(dateStr, picker.format, picker.options.useStrict); + if (options.maxDate && options.maxDate.isBefore(endYear, 'y')) { + yearsViewHeader.eq(2).addClass('disabled'); } - if (!picker.date) { - picker.date = moment(); + + while (!startYear.isAfter(endYear, 'y')) { + html += '' + startYear.year() + ''; + startYear.add(1, 'y'); } - } - picker.viewDate = moment(picker.date).startOf('month'); - fillDate(); - fillTime(); - }, - fillDow = function () { - moment.locale(picker.options.language); - var html = $('
#' + weekdaysMin[i] + '' + weekdaysMin[0] + '' + weekdaysMin[i] + '
' + currentDate.week() + '' + currentDate.date() + '
' + currentHour.format(use24Hours ? 'HH' : 'hh') + '
' + currentMinute.format('mm') + '
' + prevMonth.week() + '
' + currentSecond.format('ss') + '' + prevMonth.date() + '
' + padLeft(current.toString()) + '
' + padLeft(current.toString()) + '
' + padLeft(current.toString()) + '
' + padLeft(current.toString()) + '
' + headTemplate + '
' + - '' + - '
' + - '' + headTemplate + contTemplate + '
' + - '
' + - '
' + - '' + headTemplate + contTemplate + '
' + - '
', - ret = ''; - if (picker.options.pickDate && picker.options.pickTime) { - ret = '
'; - return ret; + if (typeof newViewMode !== 'string') { + throw new TypeError('viewMode() expects a string parameter'); } - if (picker.options.pickTime) { - return ( - '' - ); - } - return ( - '' - ); - }, - dpGlobal = { - modes: [ - { - clsName: 'days', - navFnc: 'month', - navStep: 1 - }, - { - clsName: 'months', - navFnc: 'year', - navStep: 1 - }, - { - clsName: 'years', - navFnc: 'year', - navStep: 10 - } - ] - }, + if (viewModes.indexOf(newViewMode) === -1) { + throw new TypeError('viewMode() parameter must be one of (' + viewModes.join(', ') + ') value'); + } - tpGlobal = { - hourTemplate: '', - minuteTemplate: '', - secondTemplate: '' - }; + options.viewMode = newViewMode; + currentViewMode = Math.max(viewModes.indexOf(newViewMode), minViewModeNumber); - tpGlobal.getTemplate = function () { - return ( - '
' + - '' + - '' + - '' + - '' + - '' + - (picker.options.useSeconds ? - '' : '') + - (picker.use24hours ? '' : '') + - '' + - '' + - ' ' + - '' + - ' ' + - (picker.options.useSeconds ? - '' : '') + - (picker.use24hours ? '' : '' + - '') + - '' + - '' + - '' + - '' + - '' + - (picker.options.useSeconds ? - '' : '') + - (picker.use24hours ? '' : '') + - '' + - '
' + (picker.options.useMinutes ? '' : '') + '
' + tpGlobal.hourTemplate + ':' + (picker.options.useMinutes ? tpGlobal.minuteTemplate : '00') + ':' + tpGlobal.secondTemplate + '
' + (picker.options.useMinutes ? '' : '') + '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - (picker.options.useSeconds ? - '
' : '') - ); + showMode(); + return picker; }; - picker.destroy = function () { - detachDatePickerEvents(); - detachDatePickerGlobalEvents(); - picker.widget.remove(); - picker.element.removeData('DateTimePicker'); - if (picker.component) { - picker.component.removeData('DateTimePicker'); + picker.toolbarPlacement = function (toolbarPlacement) { + if (arguments.length === 0) { + return options.toolbarPlacement; } - }; - picker.show = function (e) { - if (getPickerInput().prop('disabled')) { - return; - } - if (picker.options.useCurrent) { - if (getPickerInput().val() === '') { - if (picker.options.minuteStepping !== 1) { - var mDate = moment(), - rInterval = picker.options.minuteStepping; - mDate.minutes((Math.round(mDate.minutes() / rInterval) * rInterval) % 60).seconds(0); - picker.setValue(mDate.format(picker.format)); - } else { - picker.setValue(moment().format(picker.format)); - } - notifyChange('', e.type); - } + if (typeof toolbarPlacement !== 'string') { + throw new TypeError('toolbarPlacement() expects a string parameter'); } - // if this is a click event on the input field and picker is already open don't hide it - if (e && e.type === 'click' && picker.isInput && picker.widget.hasClass('picker-open')) { - return; + if (toolbarPlacements.indexOf(toolbarPlacement) === -1) { + throw new TypeError('toolbarPlacement() parameter must be one of (' + toolbarPlacements.join(', ') + ') value'); } - if (picker.widget.hasClass('picker-open')) { - picker.widget.hide(); - picker.widget.removeClass('picker-open'); + options.toolbarPlacement = toolbarPlacement; + + if (widget) { + hide(); + show(); } - else { - picker.widget.show(); - picker.widget.addClass('picker-open'); + return picker; + }; + + picker.widgetPositioning = function (widgetPositioning) { + if (arguments.length === 0) { + return $.extend({}, options.widgetPositioning); } - picker.height = picker.component ? picker.component.outerHeight() : picker.element.outerHeight(); - place(); - picker.element.trigger({ - type: 'dp.show', - date: moment(picker.date) - }); - attachDatePickerGlobalEvents(); - if (e) { - stopEvent(e); + + if (({}).toString.call(widgetPositioning) !== '[object Object]') { + throw new TypeError('widgetPositioning() expects an object variable'); + } + if (widgetPositioning.horizontal) { + if (typeof widgetPositioning.horizontal !== 'string') { + throw new TypeError('widgetPositioning() horizontal variable must be a string'); + } + widgetPositioning.horizontal = widgetPositioning.horizontal.toLowerCase(); + if (horizontalModes.indexOf(widgetPositioning.horizontal) === -1) { + throw new TypeError('widgetPositioning() expects horizontal parameter to be one of (' + horizontalModes.join(', ') + ')'); + } + options.widgetPositioning.horizontal = widgetPositioning.horizontal; } + if (widgetPositioning.vertical) { + if (typeof widgetPositioning.vertical !== 'string') { + throw new TypeError('widgetPositioning() vertical variable must be a string'); + } + widgetPositioning.vertical = widgetPositioning.vertical.toLowerCase(); + if (verticalModes.indexOf(widgetPositioning.vertical) === -1) { + throw new TypeError('widgetPositioning() expects vertical parameter to be one of (' + verticalModes.join(', ') + ')'); + } + options.widgetPositioning.vertical = widgetPositioning.vertical; + } + update(); + return picker; }; - picker.disable = function () { - var input = getPickerInput(); - if (input.prop('disabled')) { - return; + picker.calendarWeeks = function (showCalendarWeeks) { + if (arguments.length === 0) { + return options.calendarWeeks; } - input.prop('disabled', true); - detachDatePickerEvents(); - }; - picker.enable = function () { - var input = getPickerInput(); - if (!input.prop('disabled')) { - return; + if (typeof showCalendarWeeks !== 'boolean') { + throw new TypeError('calendarWeeks() expects parameter to be a boolean value'); } - input.prop('disabled', false); - attachDatePickerEvents(); + + options.calendarWeeks = showCalendarWeeks; + update(); + return picker; }; - picker.hide = function () { - // Ignore event if in the middle of a picker transition - var collapse = picker.widget.find('.collapse'), i, collapseData; - for (i = 0; i < collapse.length; i++) { - collapseData = collapse.eq(i).data('collapse'); - if (collapseData && collapseData.transitioning) { - return; - } + picker.showTodayButton = function (showTodayButton) { + if (arguments.length === 0) { + return options.showTodayButton; } - picker.widget.hide(); - picker.widget.removeClass('picker-open'); - picker.viewMode = picker.startViewMode; - showMode(); - picker.element.trigger({ - type: 'dp.hide', - date: moment(picker.date) - }); - detachDatePickerGlobalEvents(); - }; - picker.setValue = function (newDate) { - moment.locale(picker.options.language); - if (!newDate) { - picker.unset = true; - set(); - } else { - picker.unset = false; + if (typeof showTodayButton !== 'boolean') { + throw new TypeError('showTodayButton() expects a boolean parameter'); } - if (!moment.isMoment(newDate)) { - newDate = (newDate instanceof Date) ? moment(newDate) : moment(newDate, picker.format, picker.options.useStrict); - } else { - newDate = newDate.locale(picker.options.language); + + options.showTodayButton = showTodayButton; + if (widget) { + hide(); + show(); } - if (newDate.isValid()) { - picker.date = newDate; - set(); - picker.viewDate = moment({y: picker.date.year(), M: picker.date.month()}); - fillDate(); - fillTime(); + return picker; + }; + + picker.showClear = function (showClear) { + if (arguments.length === 0) { + return options.showClear; } - else { - notifyError(newDate); + + if (typeof showClear !== 'boolean') { + throw new TypeError('showClear() expects a boolean parameter'); } - }; - picker.getDate = function () { - if (picker.unset) { - return null; + options.showClear = showClear; + if (widget) { + hide(); + show(); } - return moment(picker.date); + return picker; }; - picker.setDate = function (date) { - var oldDate = moment(picker.date); - if (!date) { - picker.setValue(null); - } else { - picker.setValue(date); + picker.widgetParent = function (widgetParent) { + if (arguments.length === 0) { + return options.widgetParent; } - notifyChange(oldDate, 'function'); - }; - picker.setDisabledDates = function (dates) { - picker.options.disabledDates = indexGivenDates(dates); - if (picker.viewDate) { - update(); + if (typeof widgetParent === 'string') { + widgetParent = $(widgetParent); } - }; - picker.setEnabledDates = function (dates) { - picker.options.enabledDates = indexGivenDates(dates); - if (picker.viewDate) { - update(); + if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof jQuery))) { + throw new TypeError('widgetParent() expects a string or a jQuery object parameter'); } - }; - picker.setMaxDate = function (date) { - if (date === undefined) { - return; + options.widgetParent = widgetParent; + if (widget) { + hide(); + show(); } - if (moment.isMoment(date) || date instanceof Date) { - picker.options.maxDate = moment(date); - } else { - picker.options.maxDate = moment(date, picker.format, picker.options.useStrict); + return picker; + }; + + picker.keepOpen = function (keepOpen) { + if (arguments.length === 0) { + return options.format; } - if (picker.viewDate) { - update(); + + if (typeof keepOpen !== 'boolean') { + throw new TypeError('keepOpen() expects a boolean parameter'); } + + options.keepOpen = keepOpen; + return picker; }; - picker.setMinDate = function (date) { - if (date === undefined) { - return; + // initializing element and component attributes + if (element.is('input')) { + input = element; + } else { + input = element.find('.datepickerinput'); + if (input.size() === 0) { + input = element.find('input'); + } else if (!input.is('input')) { + throw new Error('CSS class "datepickerinput" cannot be applied to non input element'); } - if (moment.isMoment(date) || date instanceof Date) { - picker.options.minDate = moment(date); + } + + if (element.hasClass('input-group')) { + // in case there is more then one 'input-group-addon' Issue #48 + if (element.find('.datepickerbutton').size() === 0) { + component = element.find('[class^="input-group-"]'); } else { - picker.options.minDate = moment(date, picker.format, picker.options.useStrict); - } - if (picker.viewDate) { - update(); + component = element.find('.datepickerbutton'); } - }; + } + + if (!input.is('input')) { + throw new Error('Could not initialize DateTimePicker without an input element'); + } + + $.extend(true, options, dataToOptions()); + + picker.options(options); + + initFormatting(); + + attachDatePickerElementEvents(); + + if (input.prop('disabled')) { + picker.disable(); + } + + if (input.val().trim().length !== 0) { + setValue(parseInputDate(input.val().trim())); + } else if (options.defaultDate) { + setValue(options.defaultDate); + } - init(); + return picker; }; + /******************************************************************************** + * + * jQuery plugin constructor and defaults object + * + ********************************************************************************/ + $.fn.datetimepicker = function (options) { return this.each(function () { - var $this = $(this), - data = $this.data('DateTimePicker'); - if (!data) { - $this.data('DateTimePicker', new DateTimePicker(this, options)); + var $this = $(this); + if (!$this.data('DateTimePicker')) { + // create a private copy of the defaults object + options = $.extend(true, {}, $.fn.datetimepicker.defaults, options); + $this.data('DateTimePicker', dateTimePicker($this, options)); } }); }; $.fn.datetimepicker.defaults = { format: false, - pickDate: true, - pickTime: true, - useMinutes: true, - useSeconds: false, + dayViewHeaderFormat: 'MMMM YYYY', + extraFormats: false, + stepping: 1, + minDate: false, + maxDate: false, useCurrent: true, - calendarWeeks: false, - minuteStepping: 1, - minDate: moment({y: 1900}), - maxDate: moment().add(100, 'y'), - showToday: true, collapse: true, - language: moment.locale(), - defaultDate: '', + locale: moment.locale(), + defaultDate: false, disabledDates: false, enabledDates: false, - icons: {}, + icons: { + time: 'glyphicon glyphicon-time', + date: 'glyphicon glyphicon-calendar', + up: 'glyphicon glyphicon-chevron-up', + down: 'glyphicon glyphicon-chevron-down', + previous: 'glyphicon glyphicon-chevron-left', + next: 'glyphicon glyphicon-chevron-right', + today: 'glyphicon glyphicon-screenshot', + clear: 'glyphicon glyphicon-trash' + }, useStrict: false, - direction: 'auto', sideBySide: false, daysOfWeekDisabled: [], - widgetParent: false + calendarWeeks: false, + viewMode: 'days', + toolbarPlacement: 'default', + showTodayButton: false, + showClear: false, + widgetPositioning: { + horizontal: 'auto', + vertical: 'auto' + }, + widgetParent: null, + keepOpen: false }; })); diff --git a/src/less/_bootstrap-datetimepicker.less b/src/less/_bootstrap-datetimepicker.less new file mode 100644 index 000000000..ca43c53a3 --- /dev/null +++ b/src/less/_bootstrap-datetimepicker.less @@ -0,0 +1,307 @@ +/*! + * Datetimepicker for Bootstrap 3 +//! version : 4.0.0-beta + * https://github.com/Eonasdan/bootstrap-datetimepicker/ + */ +.bootstrap-datetimepicker-widget { + &.dropdown-menu { + margin: 2px 0; + padding: 4px; + width: 19em; + + &.timepicker-sbs { + @media (min-width: @screen-sm-min) { + width: 38em; + } + @media (min-width: @screen-md-min) { + width: 38em; + } + @media (min-width: @screen-lg-min) { + width: 38em; + } + } + + &:before, &:after { + content: ''; + display: inline-block; + position: absolute; + } + + &.bottom { + &:before { + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-bottom: 7px solid #ccc; + border-bottom-color: rgba(0,0,0,.2); + top: -7px; + left: 7px; + } + + &:after { + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid white; + top: -6px; + left: 8px; + } + } + + &.top { + &:before { + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-top: 7px solid #ccc; + border-top-color: rgba(0,0,0,.2); + bottom: -7px; + left: 6px; + } + + &:after { + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid white; + bottom: -6px; + left: 7px; + } + } + + &.pull-right { + &:before { + left: auto; + right: 6px; + } + + &:after { + left: auto; + right: 7px; + } + } + } + + .list-unstyled { + margin: 0; + } + + a[data-action] { + padding: 6px 0; + } + + a[data-action]:active { + box-shadow: none; + } + + .timepicker-hour, .timepicker-minute, .timepicker-second { + width: 54px; + font-weight: bold; + font-size: 1.2em; + margin: 0; + } + + button[data-action] { + padding: 6px; + } + + .btn[data-action="incrementHours"]::after { + .sr-only(); + content: "Increment Hours"; + } + .btn[data-action="incrementMinutes"]::after { + .sr-only(); + content: "Increment Minutes"; + } + .btn[data-action="decrementHours"]::after { + .sr-only(); + content: "Decrement Hours"; + } + .btn[data-action="decrementMinutes"]::after { + .sr-only(); + content: "Decrement Minutes"; + } + .btn[data-action="showHours"]::after { + .sr-only(); + content: "Show Hours"; + } + .btn[data-action="showMinutes"]::after { + .sr-only(); + content: "Show Minutes"; + } + .btn[data-action="togglePeriod"]::after { + .sr-only(); + content: "Toggle AM/PM"; + } + + .picker-switch { + text-align: center; + &::after { + .sr-only(); + content: "Toggle Date and Time Screens"; + } + td { + padding: 0; + margin: 0; + height: auto; + width: auto; + line-height: inherit; + span { + line-height: 2.5; + height: 2.5em; + width: 100%; + } + } + } + + table { + width: 100%; + margin: 0; + } + + td, + th { + text-align: center; + border-radius: @border-radius-base; + } + + th { + height: 20px; + line-height: 20px; + width: 20px; + + &.picker-switch { + width: 145px; + } + + &.disabled, + &.disabled:hover { + background: none; + color: @gray-light; + cursor: not-allowed; + } + + &.prev::after { + .sr-only(); + content: "Previous Month"; + } + &.next::after { + .sr-only(); + content: "Next Month"; + } + } + + thead tr:first-child th { + cursor: pointer; + + &:hover { + background: @gray-lighter; + } + } + + td { + height: 54px; + line-height: 54px; + width: 54px; + + &.cw { + font-size: .8em; + height: 20px; + line-height: 20px; + color: @gray-light; + } + + &.day + { + height: 20px; + line-height: 20px; + width: 20px; + } + + &.day:hover, + &.hour:hover, + &.minute:hover, + &.second:hover { + background: @gray-lighter; + cursor: pointer; + } + + &.old, + &.new { + color: @gray-light; + } + + &.today { + position: relative; + + &:before { + content: ''; + display: inline-block; + border-left: 7px solid transparent; + border-bottom: 7px solid @btn-primary-bg; + border-top-color: rgba(0, 0, 0, 0.2); + position: absolute; + bottom: 4px; + right: 4px; + } + } + + &.active, + &.active:hover { + background-color: @btn-primary-bg; + color: @btn-primary-color; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + } + + &.active.today:before { + border-bottom-color: #fff; + } + + &.disabled, + &.disabled:hover { + background: none; + color: @gray-light; + cursor: not-allowed; + } + + span { + display: inline-block; + width: 54px; + height: 54px; + line-height: 54px; + margin: 2px 1.5px; + cursor: pointer; + border-radius: @border-radius-base; + + &:hover { + background: @gray-lighter; + } + + &.active { + background-color: @btn-primary-bg; + color: @btn-primary-color; + text-shadow: 0 -1px 0 rgba(0,0,0,.25); + } + + &.old { + color: @gray-light; + } + + &.disabled, + &.disabled:hover { + background: none; + color: @gray-light; + cursor: not-allowed; + } + } + } + + &.usetwentyfour { + td.hour { + height: 27px; + line-height: 27px; + } + } +} + +.input-group.date { + & .input-group-addon { + cursor: pointer; + } +} \ No newline at end of file diff --git a/src/less/bootstrap-datetimepicker-build.less b/src/less/bootstrap-datetimepicker-build.less index 4a1737015..a65f78755 100644 --- a/src/less/bootstrap-datetimepicker-build.less +++ b/src/less/bootstrap-datetimepicker-build.less @@ -2,4 +2,16 @@ @import "../../node_modules/bootstrap/less/variables.less"; // Import datepicker component -@import "bootstrap-datetimepicker.less"; +@import "_bootstrap-datetimepicker.less"; + + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0,0,0,0); + border: 0; +} \ No newline at end of file diff --git a/src/nuget/Bootstrap.v3.Datetimepicker.CSS.nuspec b/src/nuget/Bootstrap.v3.Datetimepicker.CSS.nuspec index 4192e1eb7..8f2add7ef 100644 --- a/src/nuget/Bootstrap.v3.Datetimepicker.CSS.nuspec +++ b/src/nuget/Bootstrap.v3.Datetimepicker.CSS.nuspec @@ -2,7 +2,7 @@ Bootstrap.v3.Datetimepicker.CSS - 3.1.2 + 4.0.0 Bootstrap 3 Datetimepicker CSS Eonasdan Eonasdan @@ -12,12 +12,12 @@ For usage, installation and demos see Project Site on GitHub -For CSS version install Bootstrap.v3.Datetimepicker.CSS +For LESS version install Bootstrap.v3.Datetimepicker Check the change log on Github at https://github.com/Eonasdan/bootstrap-datetimepicker/wiki/Change-Log bootstrap date time picker datetimepicker datepicker jquery - + diff --git a/src/nuget/Bootstrap.v3.Datetimepicker.nuspec b/src/nuget/Bootstrap.v3.Datetimepicker.nuspec index 267ec06a4..2cd9551a0 100644 --- a/src/nuget/Bootstrap.v3.Datetimepicker.nuspec +++ b/src/nuget/Bootstrap.v3.Datetimepicker.nuspec @@ -2,7 +2,7 @@ Bootstrap.v3.Datetimepicker - 3.1.2 + 4.0.0 Bootstrap 3 Datetimepicker Eonasdan Eonasdan @@ -17,13 +17,13 @@ For CSS version install Bootstrap.v3.Datetimepicker.CSS bootstrap date time picker datetimepicker datepicker jquery - + - + diff --git a/test/publicApiSpec.js b/test/publicApiSpec.js new file mode 100644 index 000000000..d8b8f88ee --- /dev/null +++ b/test/publicApiSpec.js @@ -0,0 +1,497 @@ +describe('Plugin initialization and component basic construction', function () { + 'use strict'; + + it('loads jquery plugin properly', function () { + expect($('
').datetimepicker).toBeDefined(); + expect(typeof $('
').datetimepicker).toEqual('function'); + expect($('
').datetimepicker.defaults).toBeDefined(); + }); + + it('throws an Error if constructing on a structure with no input element', function () { + var dtp = $('
'); + $(document).find('body').append(dtp); + + expect(function () { + dtp = dtp.datetimepicker(); + }).toThrow(); + }); + + it('creates the component with default options on an input element', function () { + var dtp = $(''); + $(document).find('body').append(dtp); + + expect(function () { + dtp = dtp.datetimepicker(); + }).not.toThrow(); + + expect(dtp).not.toBe(null); + }); + + xit('calls destroy when Element that the component is attached is removed', function () { + var dtpElement = $('
').attr('class', 'row').append($('
').attr('class', 'col-md-12').append($(''))), + dtp; + $(document).find('body').append(dtpElement); + dtpElement.datetimepicker(); + dtp = dtpElement.data('DateTimePicker'); + spyOn(dtp, 'destroy').and.callThrough(); + dtpElement.remove(); + expect(dtp.destroy).toHaveBeenCalled(); + }); +}); + +describe('Public API method tests', function () { + 'use strict'; + var dtp, + dtpElement, + dpChangeSpy, + dpShowSpy, + dpHideSpy, + dpErrorSpy; + + beforeEach(function () { + dpChangeSpy = jasmine.createSpy('dp.change event Spy'); + dpShowSpy = jasmine.createSpy('dp.show event Spy'); + dpHideSpy = jasmine.createSpy('dp.hide event Spy'); + dpErrorSpy = jasmine.createSpy('dp.error event Spy'); + dtpElement = $('').attr('id', 'dtp'); + + $(document).find('body').append($('
').attr('class', 'row').append($('
').attr('class', 'col-md-12').append(dtpElement))); + $(document).find('body').on('dp.change', dpChangeSpy); + $(document).find('body').on('dp.show', dpShowSpy); + $(document).find('body').on('dp.hide', dpHideSpy); + $(document).find('body').on('dp.error', dpErrorSpy); + + dtpElement.datetimepicker(); + dtp = dtpElement.data('DateTimePicker'); + }); + + afterEach(function () { + dtp.destroy(); + dtpElement.remove(); + }); + + describe('configuration option name match to public api function', function () { + Object.getOwnPropertyNames($.fn.datetimepicker.defaults).forEach(function (key) { + it('has function ' + key + '()', function () { + expect(dtp[key]).toBeDefined(); + }); + }); + }); + + describe('date() function', function () { + describe('typechecking', function () { + it('accepts a null', function () { + expect(function () { + dtp.date(null); + }).not.toThrow(); + }); + + it('accepts a string', function () { + expect(function () { + dtp.date('2013/05/24'); + }).not.toThrow(); + }); + + it('accepts a Date object', function () { + expect(function () { + dtp.date(new Date()); + }).not.toThrow(); + }); + + it('accepts a Moment object', function () { + expect(function () { + dtp.date(moment()); + }).not.toThrow(); + }); + + it('does not accept undefined', function () { + expect(function () { + dtp.date(undefined); + }).toThrow(); + }); + + it('does not accept a number', function () { + expect(function () { + dtp.date(0); + }).toThrow(); + }); + + it('does not accept a generic Object', function () { + expect(function () { + dtp.date({}); + }).toThrow(); + }); + + it('does not accept a boolean', function () { + expect(function () { + dtp.date(false); + }).toThrow(); + }); + }); + + describe('functionality', function () { + it('has no date set upon construction', function () { + expect(dtp.date()).toBe(null); + }); + + it('sets the date correctly', function () { + var timestamp = moment(); + dtp.date(timestamp); + expect(dtp.date().isSame(timestamp)).toBe(true); + }); + }); + }); + + describe('format() function', function () { + describe('typechecking', function () { + it('accepts a false value', function () { + expect(function () { + dtp.format(false); + }).not.toThrow(); + }); + + it('accepts a string', function () { + expect(function () { + dtp.format('YYYY-MM-DD'); + }).not.toThrow(); + }); + + it('does not accept undefined', function () { + expect(function () { + dtp.format(undefined); + }).toThrow(); + }); + + it('does not accept true', function () { + expect(function () { + dtp.format(true); + }).toThrow(); + }); + + it('does not accept a generic Object', function () { + expect(function () { + dtp.format({}); + }).toThrow(); + }); + }); + + describe('functionality', function () { + it('returns no format before format is set', function () { + expect(dtp.format()).toBe(false); + }); + + it('sets the format correctly', function () { + dtp.format('YYYY-MM-DD'); + expect(dtp.format()).toBe('YYYY-MM-DD'); + }); + }); + }); + + describe('destroy() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.destroy).toBeDefined(); + }); + }); + }); + + describe('toggle() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.toggle).toBeDefined(); + }); + }); + + // describe('functionality', function () { + // it('') + // }); + }); + + describe('show() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.show).toBeDefined(); + }); + }); + + describe('functionality', function () { + it('emits a show event when called while widget is hidden', function () { + dtp.show(); + expect(dpShowSpy).toHaveBeenCalled(); + }); + + it('does not emit a show event when called and widget is already showing', function () { + dtp.hide(); + dtp.show(); + dpShowSpy.calls.reset(); + dtp.show(); + expect(dpShowSpy).not.toHaveBeenCalled(); + }); + + it('actually shows the widget', function () { + dtp.show(); + expect($(document).find('body').find('.bootstrap-datetimepicker-widget').length).toEqual(1); + }); + }); + }); + + describe('hide() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.hide).toBeDefined(); + }); + }); + + describe('functionality', function () { + it('emits a hide event when called while widget is shown', function () { + dtp.show(); + dtp.hide(); + expect(dpHideSpy).toHaveBeenCalled(); + }); + + it('does not emit a hide event when called while widget is hidden', function () { + dtp.hide(); + expect(dpHideSpy).not.toHaveBeenCalled(); + }); + + it('actually hides the widget', function () { + dtp.show(); + dtp.hide(); + expect($(document).find('body').find('.bootstrap-datetimepicker-widget').length).toEqual(0); + }); + }); + }); + + describe('disable() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.disable).toBeDefined(); + }); + }); + }); + + describe('enable() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.enable).toBeDefined(); + }); + }); + }); + + describe('options() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.options).toBeDefined(); + }); + }); + }); + + describe('disabledDates() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.disabledDates).toBeDefined(); + }); + }); + }); + + describe('enabledDates() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.enabledDates).toBeDefined(); + }); + }); + }); + + describe('daysOfWeekDisabled() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.daysOfWeekDisabled).toBeDefined(); + }); + }); + }); + + describe('maxDate() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.maxDate).toBeDefined(); + }); + }); + }); + + describe('minDate() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.minDate).toBeDefined(); + }); + }); + }); + + describe('defaultDate() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.defaultDate).toBeDefined(); + }); + }); + describe('functionality', function () { + it('returns no defaultDate before defaultDate is set', function () { + expect(dtp.defaultDate()).toBe(false); + }); + + it('sets the defaultDate correctly', function () { + var timestamp = moment(); + dtp.defaultDate(timestamp); + expect(dtp.defaultDate().isSame(timestamp)).toBe(true); + expect(dtp.date().isSame(timestamp)).toBe(true); + }); + + it('triggers a change event upon setting a default date and input field is empty', function () { + dtp.date(null); + dtp.defaultDate(moment()); + expect(dpChangeSpy).toHaveBeenCalled(); + }); + + it('does not override input value if it already has one', function () { + var timestamp = moment(); + dtp.date(timestamp); + dtp.defaultDate(moment().year(2000)); + expect(dtp.date().isSame(timestamp)).toBe(true); + }); + }); + }); + + describe('locale() function', function () { + describe('functionality', function () { + it('it has the same locale as the global moment locale with default options', function () { + expect(dtp.locale()).toBe(moment.locale()); + }); + + it('it switches to a selected locale without affecting global moment locale', function () { + dtp.locale('el'); + dtp.date(moment()); + expect(dtp.locale()).toBe('el'); + expect(dtp.date().locale()).toBe('el'); + expect(moment.locale()).toBe('en'); + }); + }); + }); + + describe('useCurrent() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.useCurrent).toBeDefined(); + }); + }); + describe('check type and parameter validity', function () { + it('accepts either a boolean value or string', function () { + var useCurrentOptions = ['year', 'month', 'day', 'hour', 'minute']; + + expect(function () { + dtp.useCurrent(false); + }).not.toThrow(); + expect(function () { + dtp.useCurrent(true); + }).not.toThrow(); + + useCurrentOptions.forEach(function (value) { + expect(function () { + dtp.useCurrent(value); + }).not.toThrow(); + }); + + expect(function () { + dtp.useCurrent('test'); + }).toThrow(); + expect(function () { + dtp.useCurrent({}); + }).toThrow(); + }); + }); + describe('functionality', function () { + it('triggers a change event upon show() and input field is empty', function () { + dtp.useCurrent(true); + dtp.show(); + expect(dpChangeSpy).toHaveBeenCalled(); + }); + }); + }); + + describe('stepping() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.stepping).toBeDefined(); + }); + }); + }); + + describe('collapse() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.collapse).toBeDefined(); + }); + }); + }); + + describe('icons() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.icons).toBeDefined(); + }); + }); + }); + + describe('useStrict() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.useStrict).toBeDefined(); + }); + }); + }); + + describe('sideBySide() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.sideBySide).toBeDefined(); + }); + }); + }); + + describe('viewMode() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.viewMode).toBeDefined(); + }); + }); + }); + + describe('widgetPositioning() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.widgetPositioning).toBeDefined(); + }); + }); + }); + + describe('calendarWeeks() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.calendarWeeks).toBeDefined(); + }); + }); + }); + + describe('showTodayButton() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.showTodayButton).toBeDefined(); + }); + }); + }); + + describe('showClear() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.showClear).toBeDefined(); + }); + }); + }); +});