diff --git a/html/js/datetime/.jscs.json b/html/js/datetime/.jscs.json index 1ce31f827..8af2b6139 100644 --- a/html/js/datetime/.jscs.json +++ b/html/js/datetime/.jscs.json @@ -54,7 +54,6 @@ "requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties", "disallowKeywords": ["with"], "disallowMultipleLineStrings": true, - "validateLineBreaks": "LF", "validateIndentation": 4, "disallowTrailingWhitespace": true, "disallowTrailingComma": true, diff --git a/html/js/datetime/CONTRIBUTING.md b/html/js/datetime/CONTRIBUTING.md index 461fef02d..6b319c1f6 100644 --- a/html/js/datetime/CONTRIBUTING.md +++ b/html/js/datetime/CONTRIBUTING.md @@ -1,7 +1,9 @@ Submitting Issues ================= -If you are submitting a bug, please test and/or fork [this jsfiddle](http://jsfiddle.net/kmbo576p/) 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/Eonasdan/0Ltv25o8/) demonstrating the issue. Code issues and fringe case bugs that do not include a jsfiddle (or similar) will be closed. + +Issues that are submitted without a description (title only) will be closed with no further explanation. Contributing code ================= @@ -22,6 +24,9 @@ Very important notes * **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. + * Pull requests that do not include a description (title only) and the following will be closed: + * What the change does + * A use case (for new features or enhancements) Grunt tasks =========== @@ -30,3 +35,4 @@ We use Grunt for managing the build. Here are some useful Grunt tasks: * `grunt` The default task lints the code and runs the tests. You should make sure you do this before submitting a PR. * `grunt build` Compiles the less stylesheet and minifies the javascript source in build directory. + * `grunt build:travis` Compliles and runs the jasmine/travis tests. **All PR's MUST pass tests in place** diff --git a/html/js/datetime/Gruntfile.js b/html/js/datetime/Gruntfile.js index cf1ade14c..9aa026ca4 100644 --- a/html/js/datetime/Gruntfile.js +++ b/html/js/datetime/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/html/js/datetime/LICENSE b/html/js/datetime/LICENSE index 47f5de70e..f8071d73e 100644 --- a/html/js/datetime/LICENSE +++ b/html/js/datetime/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/html/js/datetime/README.md b/html/js/datetime/README.md index dbe1d698a..3b4df255f 100644 --- a/html/js/datetime/README.md +++ b/html/js/datetime/README.md @@ -1,17 +1,25 @@ -# Bootstrap v3 datetimepicker widget ![GitHub version](https://badge.fury.io/gh/Eonasdan%2Fbootstrap-datetimepicker.png)   ![Travis](https://travis-ci.org/Eonasdan/bootstrap-datetimepicker.svg?branch=development) +# 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/) +#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/kmbo576p/) 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. +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 +## [Installation instructions](http://eonasdan.github.io/bootstrap-datetimepicker/Installing/) -## [Change Log](https://github.com/Eonasdan/bootstrap-datetimepicker/wiki/Change-Log) -The change log has moved to the wiki +## [Change Log](http://eonasdan.github.io/bootstrap-datetimepicker/Version%204%20Changelog/) diff --git a/html/js/datetime/bower.json b/html/js/datetime/bower.json index aaf6fcb12..34ab9314c 100644 --- a/html/js/datetime/bower.json +++ b/html/js/datetime/bower.json @@ -1,13 +1,15 @@ { "name": "eonasdan-bootstrap-datetimepicker", - "version": "3.1.3", + "version": "4.7.14", "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/html/js/datetime/build/css/bootstrap-datetimepicker.css b/html/js/datetime/build/css/bootstrap-datetimepicker.css index bd37b08b3..c70216196 100644 --- a/html/js/datetime/build/css/bootstrap-datetimepicker.css +++ b/html/js/datetime/build/css/bootstrap-datetimepicker.css @@ -1,75 +1,76 @@ /*! - * Datetimepicker for Bootstrap v3 -//! version : 3.1.3 + * Datetimepicker for Bootstrap 3 + * ! version : 4.7.14 * https://github.com/Eonasdan/bootstrap-datetimepicker/ */ .bootstrap-datetimepicker-widget { - top: 0; - left: 0; - width: 250px; + list-style: none; +} +.bootstrap-datetimepicker-widget.dropdown-menu { + margin: 2px 0; padding: 4px; - margin-top: 1px; - z-index: 99999 !important; - border-radius: 4px; + width: 19em; } -.bootstrap-datetimepicker-widget.timepicker-sbs { - width: 600px; +@media (min-width: 768px) { + .bootstrap-datetimepicker-widget.dropdown-menu.timepicker-sbs { + width: 38em; + } } -.bootstrap-datetimepicker-widget.bottom:before { +@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: 7px solid #cccccc; 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: 7px solid #cccccc; 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,82 +90,238 @@ .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 .datepicker > div { - display: none; +.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 .btn[data-action="clear"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Clear the picker"; +} +.bootstrap-datetimepicker-widget .btn[data-action="today"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Set the date to today"; } .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 { +.bootstrap-datetimepicker-widget table td, +.bootstrap-datetimepicker-widget table 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: #777777; -} -.bootstrap-datetimepicker-widget td.day { +.bootstrap-datetimepicker-widget table th { 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 { +.bootstrap-datetimepicker-widget table th.picker-switch { + width: 145px; +} +.bootstrap-datetimepicker-widget table th.disabled, +.bootstrap-datetimepicker-widget table th.disabled:hover { + background: none; + color: #777777; + cursor: not-allowed; +} +.bootstrap-datetimepicker-widget table 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 table 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 table thead tr:first-child th { + cursor: pointer; +} +.bootstrap-datetimepicker-widget table thead tr:first-child th:hover { + background: #eeeeee; +} +.bootstrap-datetimepicker-widget table td { + height: 54px; + line-height: 54px; + width: 54px; +} +.bootstrap-datetimepicker-widget table td.cw { + font-size: .8em; + height: 20px; + line-height: 20px; + color: #777777; +} +.bootstrap-datetimepicker-widget table td.day { + height: 20px; + line-height: 20px; + width: 20px; +} +.bootstrap-datetimepicker-widget table td.day:hover, +.bootstrap-datetimepicker-widget table td.hour:hover, +.bootstrap-datetimepicker-widget table td.minute:hover, +.bootstrap-datetimepicker-widget table td.second:hover { background: #eeeeee; cursor: pointer; } -.bootstrap-datetimepicker-widget td.old, -.bootstrap-datetimepicker-widget td.new { +.bootstrap-datetimepicker-widget table td.old, +.bootstrap-datetimepicker-widget table td.new { color: #777777; } -.bootstrap-datetimepicker-widget td.today { +.bootstrap-datetimepicker-widget table td.today { position: relative; } -.bootstrap-datetimepicker-widget td.today:before { +.bootstrap-datetimepicker-widget table td.today:before { content: ''; display: inline-block; - border-left: 7px solid transparent; - border-bottom: 7px solid #428bca; + border: 0 0 7px 7px solid transparent; + border-bottom-color: #337ab7; border-top-color: rgba(0, 0, 0, 0.2); position: absolute; bottom: 4px; right: 4px; } -.bootstrap-datetimepicker-widget td.active, -.bootstrap-datetimepicker-widget td.active:hover { - background-color: #428bca; +.bootstrap-datetimepicker-widget table td.active, +.bootstrap-datetimepicker-widget table td.active:hover { + background-color: #337ab7; color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } -.bootstrap-datetimepicker-widget td.active.today:before { +.bootstrap-datetimepicker-widget table td.active.today:before { border-bottom-color: #fff; } -.bootstrap-datetimepicker-widget td.disabled, -.bootstrap-datetimepicker-widget td.disabled:hover { +.bootstrap-datetimepicker-widget table td.disabled, +.bootstrap-datetimepicker-widget table td.disabled:hover { background: none; color: #777777; cursor: not-allowed; } -.bootstrap-datetimepicker-widget td span { +.bootstrap-datetimepicker-widget table td span { display: inline-block; width: 54px; height: 54px; @@ -173,66 +330,37 @@ cursor: pointer; border-radius: 4px; } -.bootstrap-datetimepicker-widget td span:hover { +.bootstrap-datetimepicker-widget table td span:hover { background: #eeeeee; } -.bootstrap-datetimepicker-widget td span.active { - background-color: #428bca; +.bootstrap-datetimepicker-widget table td span.active { + background-color: #337ab7; color: #ffffff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } -.bootstrap-datetimepicker-widget td span.old { +.bootstrap-datetimepicker-widget table td span.old { color: #777777; } -.bootstrap-datetimepicker-widget td span.disabled, -.bootstrap-datetimepicker-widget td span.disabled:hover { +.bootstrap-datetimepicker-widget table td span.disabled, +.bootstrap-datetimepicker-widget table td span.disabled:hover { background: none; 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/html/js/datetime/build/css/bootstrap-datetimepicker.min.css b/html/js/datetime/build/css/bootstrap-datetimepicker.min.css index cf838a3c2..c70216196 100644 --- a/html/js/datetime/build/css/bootstrap-datetimepicker.min.css +++ b/html/js/datetime/build/css/bootstrap-datetimepicker.min.css @@ -1,5 +1,366 @@ /*! - * Datetimepicker for Bootstrap v3 -//! version : 3.1.3 + * Datetimepicker for Bootstrap 3 + * ! version : 4.7.14 * 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 { + list-style: none; +} +.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 #cccccc; + border-bottom-color: rgba(0, 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 white; + 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 #cccccc; + border-top-color: rgba(0, 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 white; + 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: bold; + 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 .btn[data-action="clear"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Clear the picker"; +} +.bootstrap-datetimepicker-widget .btn[data-action="today"]::after { + position: absolute; + width: 1px; + height: 1px; + margin: -1px; + padding: 0; + overflow: hidden; + clip: rect(0, 0, 0, 0); + border: 0; + content: "Set the date to today"; +} +.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 table td, +.bootstrap-datetimepicker-widget table th { + text-align: center; + border-radius: 4px; +} +.bootstrap-datetimepicker-widget table th { + height: 20px; + line-height: 20px; + width: 20px; +} +.bootstrap-datetimepicker-widget table th.picker-switch { + width: 145px; +} +.bootstrap-datetimepicker-widget table th.disabled, +.bootstrap-datetimepicker-widget table th.disabled:hover { + background: none; + color: #777777; + cursor: not-allowed; +} +.bootstrap-datetimepicker-widget table 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 table 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 table thead tr:first-child th { + cursor: pointer; +} +.bootstrap-datetimepicker-widget table thead tr:first-child th:hover { + background: #eeeeee; +} +.bootstrap-datetimepicker-widget table td { + height: 54px; + line-height: 54px; + width: 54px; +} +.bootstrap-datetimepicker-widget table td.cw { + font-size: .8em; + height: 20px; + line-height: 20px; + color: #777777; +} +.bootstrap-datetimepicker-widget table td.day { + height: 20px; + line-height: 20px; + width: 20px; +} +.bootstrap-datetimepicker-widget table td.day:hover, +.bootstrap-datetimepicker-widget table td.hour:hover, +.bootstrap-datetimepicker-widget table td.minute:hover, +.bootstrap-datetimepicker-widget table td.second:hover { + background: #eeeeee; + cursor: pointer; +} +.bootstrap-datetimepicker-widget table td.old, +.bootstrap-datetimepicker-widget table td.new { + color: #777777; +} +.bootstrap-datetimepicker-widget table td.today { + position: relative; +} +.bootstrap-datetimepicker-widget table td.today:before { + content: ''; + display: inline-block; + border: 0 0 7px 7px solid transparent; + border-bottom-color: #337ab7; + border-top-color: rgba(0, 0, 0, 0.2); + position: absolute; + bottom: 4px; + right: 4px; +} +.bootstrap-datetimepicker-widget table td.active, +.bootstrap-datetimepicker-widget table td.active:hover { + background-color: #337ab7; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.bootstrap-datetimepicker-widget table td.active.today:before { + border-bottom-color: #fff; +} +.bootstrap-datetimepicker-widget table td.disabled, +.bootstrap-datetimepicker-widget table td.disabled:hover { + background: none; + color: #777777; + cursor: not-allowed; +} +.bootstrap-datetimepicker-widget table td span { + display: inline-block; + width: 54px; + height: 54px; + line-height: 54px; + margin: 2px 1.5px; + cursor: pointer; + border-radius: 4px; +} +.bootstrap-datetimepicker-widget table td span:hover { + background: #eeeeee; +} +.bootstrap-datetimepicker-widget table td span.active { + background-color: #337ab7; + color: #ffffff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.bootstrap-datetimepicker-widget table td span.old { + color: #777777; +} +.bootstrap-datetimepicker-widget table td span.disabled, +.bootstrap-datetimepicker-widget table td span.disabled:hover { + background: none; + color: #777777; + 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; +} diff --git a/html/js/datetime/build/js/bootstrap-datetimepicker.min.js b/html/js/datetime/build/js/bootstrap-datetimepicker.min.js index cdba4b105..a60af89d8 100644 --- a/html/js/datetime/build/js/bootstrap-datetimepicker.min.js +++ b/html/js/datetime/build/js/bootstrap-datetimepicker.min.js @@ -1 +1,8 @@ -!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}},y=function(){return x("h")||x("m")||x("s")},z=function(){return x("y")||x("M")||x("d")},A=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()))]},B=function(){var b=a(""),c=a(""),e=a("");return x("h")&&(b.append(a("
").append(a("").attr({href:"#",tabindex:"-1"}).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:"#",tabindex:"-1"}).addClass("btn").attr("data-action","decrementHours").append(a("").addClass(d.icons.down))))),x("m")&&(x("h")&&(b.append(a("").addClass("separator")),c.append(a("").addClass("separator").html(":")),e.append(a("").addClass("separator"))),b.append(a("").append(a("").attr({href:"#",tabindex:"-1"}).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:"#",tabindex:"-1"}).addClass("btn").attr("data-action","decrementMinutes").append(a("").addClass(d.icons.down))))),x("s")&&(x("m")&&(b.append(a("").addClass("separator")),c.append(a("").addClass("separator").html(":")),e.append(a("").addClass("separator"))),b.append(a("").append(a("").attr({href:"#",tabindex:"-1"}).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:"#",tabindex:"-1"}).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]))},C=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=[B()];return x("h")&&e.push(b),x("m")&&e.push(c),x("s")&&e.push(d),e},D=function(){var b=[];return d.showTodayButton&&b.push(a("
").append(a("").attr("data-action","today").append(a("").addClass(d.icons.today)))),!d.sideBySide&&z()&&y()&&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)))),d.showClose&&b.push(a("").append(a("").attr("data-action","close").append(a("").addClass(d.icons.close)))),a("").addClass("table-condensed").append(a("").append(a("").append(b)))},E=function(){var b=a("
").addClass("bootstrap-datetimepicker-widget dropdown-menu"),c=a("
").addClass("datepicker").append(A()),e=a("
").addClass("timepicker").append(C()),g=a("
    ").addClass("list-unstyled"),h=a("
  • ").addClass("picker-switch"+(d.collapse?" accordion-toggle":"")).append(D());return d.inline&&b.removeClass("dropdown-menu"),f&&b.addClass("usetwentyfour"),d.sideBySide&&z()&&y()?(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),z()&&g.append(a("
  • ").addClass(d.collapse&&y()?"collapse in":"").append(c)),"default"===d.toolbarPlacement&&g.append(h),y()&&g.append(a("
  • ").addClass(d.collapse&&z()?"collapse":"").append(e)),"bottom"===d.toolbarPlacement&&g.append(h),b.append(g))},F=function(){var b,e={};return b=c.is("input")||d.inline?c.data():c.find("input").data(),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},G=function(){var b,e=(n||c).position(),f=(n||c).offset(),g=d.widgetPositioning.vertical,h=d.widgetPositioning.horizontal;if(d.widgetParent)b=d.widgetParent.append(o);else if(c.is("input"))b=c.parent().append(o);else{if(d.inline)return void(b=c.append(o));b=c,c.children().first().after(o)}if("auto"===g&&(g=f.top+1.5*o.height()>=a(window).height()+a(window).scrollTop()&&o.height()+c.outerHeight()a(window).width()?"right":"left"),"top"===g?o.addClass("top").removeClass("bottom"):o.addClass("bottom").removeClass("top"),"right"===h?o.addClass("pull-right"):o.removeClass("pull-right"),"relative"!==b.css("position")&&(b=b.parents().filter(function(){return"relative"===a(this).css("position")}).first()),0===b.length)throw new Error("datetimepicker component should be placed within a relative positioned container");o.css({top:"top"===g?"auto":e.top+c.outerHeight(),bottom:"top"===g?e.top+c.outerHeight():"auto",left:"left"===h?b.css("padding-left"):"auto",right:"left"===h?"auto":b.width()-c.outerWidth()})},H=function(a){"dp.change"===a.type&&(a.date&&a.date.isSame(a.oldDate)||!a.date&&!a.oldDate)||c.trigger(a)},I=function(a){o&&(a&&(i=Math.max(p,Math.min(2,i+a))),o.find(".datepicker > div").hide().filter(".datepicker-"+q[i].clsName).show())},J=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"),M(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),O(),P()}},R=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)},S=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)},T=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)},U=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")),R(),S(),T()},V=function(){o&&(Q(),U())},W=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(M(a)?(k=a,l=k.clone(),e.val(k.format(g)),c.data("date",k.format(g)),V(),m=!1,H({type:"dp.change",date:k.clone(),oldDate:b})):(d.keepInvalid||e.val(m?"":k.format(g)),H({type:"dp.error",date:a})))):(m=!0,e.val(""),c.data("date",""),H({type:"dp.change",date:null,oldDate:b}),void V())},X=function(){var b=!1;return o?(o.find(".collapse").each(function(){var c=a(this).data("collapse");return c&&c.transitioning?(b=!0,!1):!0}),b?j:(n&&n.hasClass("btn")&&n.toggleClass("active"),o.hide(),a(window).off("resize",G),o.off("click","[data-action]"),o.off("mousedown",!1),o.remove(),o=!1,H({type:"dp.hide",date:k.clone()}),j)):j},Y=function(){W(null)},Z={next:function(){l.add(q[i].navStep,q[i].navFnc),Q()},previous:function(){l.subtract(q[i].navStep,q[i].navFnc),Q()},pickerSwitch:function(){I(1)},selectMonth:function(b){var c=a(b.target).closest("tbody").find("span").index(a(b.target));l.month(c),i===p?(W(k.clone().year(l.year()).month(l.month())),d.inline||X()):(I(-1),Q())},selectYear:function(b){var c=parseInt(a(b.target).text(),10)||0;l.year(c),i===p?(W(k.clone().year(l.year())),d.inline||X()):(I(-1),Q())},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"),W(c.date(parseInt(a(b.target).text(),10))),y()||d.keepOpen||d.inline||X()},incrementHours:function(){W(k.clone().add(1,"h"))},incrementMinutes:function(){W(k.clone().add(d.stepping,"m"))},incrementSeconds:function(){W(k.clone().add(1,"s"))},decrementHours:function(){W(k.clone().subtract(1,"h"))},decrementMinutes:function(){W(k.clone().subtract(d.stepping,"m"))},decrementSeconds:function(){W(k.clone().subtract(1,"s"))},togglePeriod:function(){W(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?(g.collapse("hide"),h.collapse("show")):(g.removeClass("in"),h.addClass("in")),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)),W(k.clone().hours(c)),Z.showPicker.call(j)},selectMinute:function(b){W(k.clone().minutes(parseInt(a(b.target).text(),10))),Z.showPicker.call(j)},selectSecond:function(b){W(k.clone().seconds(parseInt(a(b.target).text(),10))),Z.showPicker.call(j)},clear:Y,today:function(){W(b())},close:X},$=function(b){return a(b.currentTarget).is(".disabled")?!1:(Z[a(b.currentTarget).data("action")].apply(j,arguments),!1)},_=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")||!d.ignoreReadonly&&e.prop("readonly")||o?j:(d.useCurrent&&m&&(e.is("input")&&0===e.val().trim().length||d.inline)&&(c=b(),"string"==typeof d.useCurrent&&(c=f[d.useCurrent](c)),W(c)),o=E(),J(),N(),o.find(".timepicker-hours").hide(),o.find(".timepicker-minutes").hide(),o.find(".timepicker-seconds").hide(),V(),I(),a(window).on("resize",G),o.on("click","[data-action]",$),o.on("mousedown",!1),n&&n.hasClass("btn")&&n.toggleClass("active"),o.show(),G(),e.is(":focus")||e.focus(),H({type:"dp.show"}),j)},ab=function(){return o?X():_()},bb=function(a){return a=b.isMoment(a)||a instanceof Date?b(a):b(a,h,d.useStrict),a.locale(d.locale),a},cb=function(a){var b,c,e,f,g=null,h=[],i={},k=a.which,l="p";w[k]=l;for(b in w)w.hasOwnProperty(b)&&w[b]===l&&(h.push(b),parseInt(b,10)!==k&&(i[b]=!0));for(b in d.keyBinds)if(d.keyBinds.hasOwnProperty(b)&&"function"==typeof d.keyBinds[b]&&(e=b.split(" "),e.length===h.length&&v[k]===e[e.length-1])){for(f=!0,c=e.length-2;c>=0;c--)if(!(v[e[c]]in i)){f=!1;break}if(f){g=d.keyBinds[b];break}}g&&(g.call(j,o),a.stopPropagation(),a.preventDefault())},db=function(a){w[a.which]="r",a.stopPropagation(),a.preventDefault()},eb=function(b){var c=a(b.target).val().trim(),d=c?bb(c):null;return W(d),b.stopImmediatePropagation(),!1},fb=function(){e.on({change:eb,blur:d.debug?"":X,keydown:cb,keyup:db}),c.is("input")?e.on({focus:_}):n&&(n.on("click",ab),n.on("mousedown",!1))},gb=function(){e.off({change:eb,blur:X,keydown:cb,keyup:db}),c.is("input")?e.off({focus:_}):n&&(n.off("click",ab),n.off("mousedown",!1))},hb=function(b){var c={};return a.each(b,function(){var a=bb(this);a.isValid()&&(c[a.format("YYYY-MM-DD")]=!0)}),Object.keys(c).length?c:!1},ib=function(){var a=d.format||"L LT";g=a.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(a){var b=k.localeData().longDateFormat(a)||a;return b.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,x("y")&&(p=2),x("M")&&(p=1),x("d")&&(p=0),i=Math.max(p,i),m||W(k)};if(j.destroy=function(){X(),gb(),c.removeData("DateTimePicker"),c.removeData("date")},j.toggle=ab,j.show=_,j.hide=X,j.disable=function(){return X(),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.ignoreReadonly=function(a){if(0===arguments.length)return d.ignoreReadonly;if("boolean"!=typeof a)throw new TypeError("ignoreReadonly () expects a boolean parameter");return d.ignoreReadonly=a,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 W(null===a?null:bb(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&&ib(),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&&ib(),j},j.disabledDates=function(b){if(0===arguments.length)return d.disabledDates?a.extend({},d.disabledDates):d.disabledDates;if(!b)return d.disabledDates=!1,V(),j;if(!(b instanceof Array))throw new TypeError("disabledDates() expects an array parameter");return d.disabledDates=hb(b),d.enabledDates=!1,V(),j},j.enabledDates=function(b){if(0===arguments.length)return d.enabledDates?a.extend({},d.enabledDates):d.enabledDates;if(!b)return d.enabledDates=!1,V(),j;if(!(b instanceof Array))throw new TypeError("enabledDates() expects an array parameter");return d.enabledDates=hb(b),d.disabledDates=!1,V(),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(),V(),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,V(),j;"string"==typeof a&&("now"===a||"moment"===a)&&(a=b());var c=bb(a);if(!c.isValid())throw new TypeError("maxDate() Could not parse date parameter: "+a);if(d.minDate&&c.isBefore(d.minDate))throw new TypeError("maxDate() date parameter is before options.minDate: "+c.format(g));return d.maxDate=c,d.maxDate.isBefore(a)&&W(d.maxDate),l.isAfter(c)&&(l=c.clone()),V(),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,V(),j;"string"==typeof a&&("now"===a||"moment"===a)&&(a=b());var c=bb(a);if(!c.isValid())throw new TypeError("minDate() Could not parse date parameter: "+a);if(d.maxDate&&c.isAfter(d.maxDate))throw new TypeError("minDate() date parameter is after options.maxDate: "+c.format(g));return d.minDate=c,d.minDate.isAfter(a)&&W(d.minDate),l.isBefore(c)&&(l=c.clone()),V(),j},j.defaultDate=function(a){if(0===arguments.length)return d.defaultDate?d.defaultDate.clone():d.defaultDate;if(!a)return d.defaultDate=!1,j;"string"==typeof a&&("now"===a||"moment"===a)&&(a=b());var c=bb(a);if(!c.isValid())throw new TypeError("defaultDate() Could not parse date parameter: "+a);if(!M(c))throw new TypeError("defaultDate() date passed is invalid according to component setup validations");return d.defaultDate=c,d.defaultDate&&""===e.val().trim()&&void 0===e.attr("placeholder")&&W(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&&ib(),o&&(X(),_()),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&&(X(),_()),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&&(X(),_()),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&&(X(),_()),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),I(),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&&(X(),_()),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 V(),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,V(),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&&(X(),_()),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&&(X(),_()),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 a))throw new TypeError("widgetParent() expects a string or a jQuery object parameter");return d.widgetParent=b,o&&(X(),_()),j},j.keepOpen=function(a){if(0===arguments.length)return d.keepOpen;if("boolean"!=typeof a)throw new TypeError("keepOpen() expects a boolean parameter");return d.keepOpen=a,j},j.inline=function(a){if(0===arguments.length)return d.inline;if("boolean"!=typeof a)throw new TypeError("inline() expects a boolean parameter");return d.inline=a,j},j.clear=function(){return Y(),j},j.keyBinds=function(a){return d.keyBinds=a,j},j.debug=function(a){if("boolean"!=typeof a)throw new TypeError("debug() expects a boolean parameter");return d.debug=a,j},j.showClose=function(a){if(0===arguments.length)return d.showClose;if("boolean"!=typeof a)throw new TypeError("showClose() expects a boolean parameter");return d.showClose=a,j},j.keepInvalid=function(a){if(0===arguments.length)return d.keepInvalid;if("boolean"!=typeof a)throw new TypeError("keepInvalid() expects a boolean parameter");return d.keepInvalid=a,j},j.datepickerInput=function(a){if(0===arguments.length)return d.datepickerInput;if("string"!=typeof a)throw new TypeError("datepickerInput() expects a string parameter");return d.datepickerInput=a,j},c.is("input"))e=c;else if(e=c.find(d.datepickerInput),0===e.size())e=c.find("input");else if(!e.is("input"))throw new Error('CSS class "'+d.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")),!d.inline&&!e.is("input"))throw new Error("Could not initialize DateTimePicker without an input element");return a.extend(!0,d,F()),j.options(d),ib(),fb(),e.prop("disabled")&&j.disable(),e.is("input")&&0!==e.val().trim().length?W(bb(e.val().trim())):d.defaultDate&&void 0===e.attr("placeholder")&&W(d.defaultDate),d.inline&&_(),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",close:"glyphicon glyphicon-remove"},useStrict:!1,sideBySide:!1,daysOfWeekDisabled:[],calendarWeeks:!1,viewMode:"days",toolbarPlacement:"default",showTodayButton:!1,showClear:!1,showClose:!1,widgetPositioning:{horizontal:"auto",vertical:"auto"},widgetParent:null,ignoreReadonly:!1,keepOpen:!1,inline:!1,keepInvalid:!1,datepickerInput:".datepickerinput",keyBinds:{up:function(a){if(a){var c=this.date()||b();this.date(a.find(".datepicker").is(":visible")?c.clone().subtract(7,"d"):c.clone().add(1,"m"))}},down:function(a){if(!a)return void this.show();var c=this.date()||b();this.date(a.find(".datepicker").is(":visible")?c.clone().add(7,"d"):c.clone().subtract(1,"m"))},"control up":function(a){if(a){var c=this.date()||b();this.date(a.find(".datepicker").is(":visible")?c.clone().subtract(1,"y"):c.clone().add(1,"h"))}},"control down":function(a){if(a){var c=this.date()||b();this.date(a.find(".datepicker").is(":visible")?c.clone().add(1,"y"):c.clone().subtract(1,"h"))}},left:function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")&&this.date(c.clone().subtract(1,"d"))}},right:function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")&&this.date(c.clone().add(1,"d"))}},pageUp:function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")&&this.date(c.clone().subtract(1,"M"))}},pageDown:function(a){if(a){var c=this.date()||b();a.find(".datepicker").is(":visible")&&this.date(c.clone().add(1,"M"))}},enter:function(){this.hide()},escape:function(){this.hide()},"control space":function(a){a.find(".timepicker").is(":visible")&&a.find('.btn[data-action="togglePeriod"]').click()},t:function(){this.date(b())},"delete":function(){this.clear()}},debug:!1}}); \ No newline at end of file diff --git a/html/js/datetime/build/nuget/Bootstrap.v3.Datetimepicker.4.0.0.nupkg b/html/js/datetime/build/nuget/Bootstrap.v3.Datetimepicker.4.0.0.nupkg new file mode 100644 index 000000000..f38538a53 Binary files /dev/null and b/html/js/datetime/build/nuget/Bootstrap.v3.Datetimepicker.4.0.0.nupkg differ diff --git a/html/js/datetime/build/nuget/Bootstrap.v3.Datetimepicker.CSS.4.0.0.nupkg b/html/js/datetime/build/nuget/Bootstrap.v3.Datetimepicker.CSS.4.0.0.nupkg new file mode 100644 index 000000000..d10e267cf Binary files /dev/null and b/html/js/datetime/build/nuget/Bootstrap.v3.Datetimepicker.CSS.4.0.0.nupkg differ diff --git a/html/js/datetime/component.json b/html/js/datetime/component.json index fbaa84016..184d37480 100644 --- a/html/js/datetime/component.json +++ b/html/js/datetime/component.json @@ -1,10 +1,9 @@ { "name": "bootstrap-datetimepicker", - "version": "3.1.3", - "main": ["build/css/bootstrap-datetimepicker.min.css","build/js/bootstrap-datetimepicker.min.js"], + "version": "4.7.14", + "main": ["build/css/bootstrap-datetimepicker.min.css","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" } } diff --git a/html/js/datetime/composer.json b/html/js/datetime/composer.json index cf5646145..f5d733ef4 100644 --- a/html/js/datetime/composer.json +++ b/html/js/datetime/composer.json @@ -1,7 +1,7 @@ { "name": "eonasdan/bootstrap-datetimepicker", "type": "component", - "version": "3.1.3", + "version": "4.7.14", "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/html/js/datetime/package.json b/html/js/datetime/package.json index 3c2afba97..512d4f0e1 100644 --- a/html/js/datetime/package.json +++ b/html/js/datetime/package.json @@ -1,7 +1,7 @@ { "name": "bootstrap-datetimepicker", "main": "src/js/bootstrap-datetimepicker.js", - "version": "3.1.3", + "version": "4.7.14", "repository": { "type": "git", "url": "https://github.com/eonasdan/bootstrap-datetimepicker.git" @@ -15,21 +15,21 @@ "datepicker", "datetimepicker", "timepicker", - "moment" + "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/html/js/datetime/src/js/bootstrap-datetimepicker.js b/html/js/datetime/src/js/bootstrap-datetimepicker.js index 44abcc1fe..034cf5d8c 100644 --- a/html/js/datetime/src/js/bootstrap-datetimepicker.js +++ b/html/js/datetime/src/js/bootstrap-datetimepicker.js @@ -1,1384 +1,2051 @@ +/*! version : 4.7.14 + ========================================================= + bootstrap-datetimejs + https://github.com/Eonasdan/bootstrap-datetimepicker + Copyright (c) 2015 Jonathan Peterson + ========================================================= + */ /* -//! version : 3.1.3 -========================================================= -bootstrap-datetimepicker.js -https://github.com/Eonasdan/bootstrap-datetimepicker -========================================================= -The MIT License (MIT) + The MIT License (MIT) -Copyright (c) 2014 Jonathan Peterson + Copyright (c) 2015 Jonathan Peterson -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -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: + 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 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) { + 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. + */ +/*global define:false */ +/*global exports:false */ +/*global require:false */ +/*global jQuery:false */ +/*global moment:false */ +(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. - if (!jQuery) { - throw new Error('bootstrap-datetimepicker requires jQuery to be loaded first'); + } else { + // Neither AMD nor CommonJS used. Use global variables. + if (typeof jQuery === 'undefined') { + throw 'bootstrap-datetimepicker requires jQuery to be loaded first'; } - if (!moment) { - throw new Error('bootstrap-datetimepicker requires moment.js to be loaded first'); + if (typeof moment === 'undefined') { + 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().startOf('d'), + 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'], + keyMap = { + 'up': 38, + 38: 'up', + 'down': 40, + 40: 'down', + 'left': 37, + 37: 'left', + 'right': 39, + 39: 'right', + 'tab': 9, + 9: 'tab', + 'escape': 27, + 27: 'escape', + 'enter': 13, + 13: 'enter', + 'pageUp': 33, + 33: 'pageUp', + 'pageDown': 34, + 34: 'pageDown', + 'shift': 16, + 16: 'shift', + 'control': 17, + 17: 'control', + 'space': 32, + 32: 'space', + 't': 84, + 84: 't', + 'delete': 46, + 46: 'delete' + }, + keyState = {}, - DateTimePicker = function (element, options) { - var defaults = $.fn.datetimepicker.defaults, - - icons = { - time: 'glyphicon glyphicon-time', - date: 'glyphicon glyphicon-calendar', - up: 'glyphicon glyphicon-chevron-up', - down: 'glyphicon glyphicon-chevron-down' + /******************************************************************************** + * + * 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; + } }, - picker = this, - errored = false, - dDate, + hasTime = function () { + return (isEnabled('h') || isEnabled('m') || isEnabled('s')); + }, - init = function () { - var icon = false, localeData, rInterval; - picker.options = $.extend({}, defaults, options); - picker.options.icons = $.extend({}, icons, picker.options.icons); + hasDate = function () { + return (isEnabled('y') || isEnabled('M') || isEnabled('d')); + }, - picker.element = $(element); + 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)},K=function(a){return d.disabledDates[a.format("YYYY-MM-DD")]===!0},L=function(a){return d.enabledDates[a.format("YYYY-MM-DD")]===!0},M=function(a,b){return a.isValid()?d.disabledDates&&K(a)&&"M"!==b?!1:d.enabledDates&&!L(a)&&"M"!==b?!1: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},N=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)},O=function(){var b=o.find(".datepicker-months"),c=b.find("th"),d=b.find("tbody").find("span");b.find(".disabled").removeClass("disabled"),M(l.clone().subtract(1,"y"),"y")||c.eq(0).addClass("disabled"),c.eq(1).text(l.year()),M(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){M(l.clone().month(b),"M")||a(this).addClass("disabled")})},P=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)},Q=function(){var c,e,f,g=o.find(".datepicker-days"),h=g.find("th"),i=[];if(z()){for(g.find(".disabled").removeClass("disabled"),h.eq(1).text(l.format(d.dayViewHeaderFormat)),M(l.clone().subtract(1,"M"),"M")||h.eq(0).addClass("disabled"),M(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'))) + ); - dataToOptions(); + 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()) + ) + ]; + }, - if (!(picker.options.pickTime || picker.options.pickDate)) { - throw new Error('Must choose at least one picker'); - } + getTimePickerMainTemplate = function () { + var topRow = $(''), + middleRow = $(''), + bottomRow = $(''); - picker.id = dpgId++; - moment.locale(picker.options.language); - picker.date = moment(); - picker.unset = false; - picker.isInput = picker.element.is('input'); - picker.component = false; - - 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 (isEnabled('h')) { + topRow.append($('
') + .append($('').attr({href: '#', tabindex: '-1'}).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: '#', tabindex: '-1'}).addClass('btn').attr('data-action', 'decrementHours') + .append($('').addClass(options.icons.down)))); } - else { - picker.component = picker.element.find('.datepickerbutton'); - } - } - picker.format = picker.options.format; - - localeData = moment().localeData(); - - if (!picker.format) { - picker.format = (picker.options.pickDate ? localeData.longDateFormat('L') : ''); - if (picker.options.pickDate && picker.options.pickTime) { - picker.format += ' '; - } - 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'; + if (isEnabled('m')) { + if (isEnabled('h')) { + topRow.append($('').addClass('separator')); + middleRow.append($('').addClass('separator').html(':')); + bottomRow.append($('').addClass('separator')); } - else { - picker.format += ':ss'; + topRow.append($('') + .append($('').attr({href: '#', tabindex: '-1'}).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: '#', tabindex: '-1'}).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: '#', tabindex: '-1'}).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: '#', tabindex: '-1'}).addClass('btn').attr('data-action', 'decrementSeconds') + .append($('').addClass(options.icons.down)))); } - } - picker.use24hours = (picker.format.toLowerCase().indexOf('a') < 0 && picker.format.indexOf('h') < 0); - if (picker.component) { - icon = picker.component.find('span'); - } - - if (picker.options.pickTime) { - if (icon) { - icon.addClass(picker.options.icons.time); + if (!use24Hours) { + topRow.append($('').addClass('separator')); + middleRow.append($('') + .append($('').addClass('separator')); } - } - if (picker.options.pickDate) { - if (icon) { - icon.removeClass(picker.options.icons.time); - icon.addClass(picker.options.icons.date); + + return $('
').addClass('timepicker-picker') + .append($('').addClass('table-condensed') + .append([topRow, middleRow, bottomRow])); + }, + + 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); } - } - - 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'; - - picker.widget = $(getTemplate()).appendTo(picker.options.widgetParent); - - 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; + if (isEnabled('m')) { + ret.push(minutesView); } - } - 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; + if (isEnabled('s')) { + ret.push(secondsView); } - } - picker.viewMode = Math.max(picker.viewMode, picker.minViewMode); + return ret; + }, - picker.options.disabledDates = indexGivenDates(picker.options.disabledDates); - picker.options.enabledDates = indexGivenDates(picker.options.enabledDates); + 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)))); + } + if (options.showClose) { + row.push($('').append($('').attr('data-action', 'close').append($('').addClass(options.icons.close)))); + } + return $('').addClass('table-condensed').append($('').append($('').append(row))); + }, - 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); - } - }, + 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()); - getPickerInput = function () { - var input; + if (options.inline) { + template.removeClass('dropdown-menu'); + } - 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; - }, + if (use24Hours) { + template.addClass('usetwentyfour'); + } + 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; + } - 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; - } - }, + 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); + }, - place = function () { - var position = 'absolute', - offset = picker.component ? picker.component.offset() : picker.element.offset(), - $window = $(window), - placePosition; + dataToOptions = function () { + var eData, + dataOptions = {}; - 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'; + if (element.is('input') || options.inline) { + eData = element.data(); } else { - placePosition = 'bottom'; + eData = element.find('input').data(); } - } - 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 (picker.options.width !== undefined) { - picker.widget.width(picker.options.width); - } + if (eData.dateOptions && eData.dateOptions instanceof Object) { + dataOptions = $.extend(true, dataOptions, eData.dateOptions); + } - if (picker.options.orientation === 'left') { - picker.widget.addClass('left-oriented'); - offset.left = offset.left - picker.widget.width() + 20; - } - - if (isInFixed()) { - position = 'fixed'; - offset.top -= $window.scrollTop(); - offset.left -= $window.scrollLeft(); - } - - 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 (placePosition === 'top') { - picker.widget.css({ - position: position, - bottom: offset.bottom, - top: 'auto', - left: offset.left, - right: offset.right + $.each(options, function (key) { + var attributeName = 'date' + key.charAt(0).toUpperCase() + key.slice(1); + if (eData[attributeName] !== undefined) { + dataOptions[key] = eData[attributeName]; + } }); - } else { - picker.widget.css({ - position: position, - top: offset.top, - bottom: 'auto', - left: offset.left, - right: offset.right - }); - } - }, + return dataOptions; + }, - 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) - }); + place = function () { + var position = (component || element).position(), + offset = (component || element).offset(), + vertical = options.widgetPositioning.vertical, + horizontal = options.widgetPositioning.horizontal, + parent; - if (eventType !== 'change') { - picker.element.change(); - } - }, - - notifyError = function (date) { - errored = true; - picker.element.trigger({ - type: 'dp.error', - date: moment(date, picker.format, picker.options.useStrict) - }); - }, - - 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.widgetParent) { + parent = options.widgetParent.append(widget); + } else if (element.is('input')) { + parent = element.parent().append(widget); + } else if (options.inline) { + parent = element.append(widget); + return; + } else { + parent = element; + element.children().first().after(widget); } - if (!picker.date) { - picker.date = moment(); - } - } - picker.viewDate = moment(picker.date).startOf('month'); - fillDate(); - fillTime(); - }, - fillDow = function () { - moment.locale(picker.options.language); - var html = $('
'), 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(''); - } - } else { - for (i = 1; i < 8; i++) { - if (i === 7) { - html.append(''); + // Top and bottom logic + if (vertical === 'auto') { + if (offset.top + widget.height() * 1.5 >= $(window).height() + $(window).scrollTop() && + widget.height() + element.outerHeight() < offset.top) { + vertical = 'top'; } else { - html.append(''); + vertical = 'bottom'; } } - } - 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); - }, - - 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(); - - 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'); - - picker.widget.find('.datepicker-days th:eq(1)').text( - months[month] + ' ' + year); - - 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'); - } - - nextMonth = moment(prevMonth).add(42, 'd'); - while (prevMonth.isBefore(nextMonth)) { - if (prevMonth.weekday() === moment().startOf('week').weekday()) { - row = $(''); - html.push(row); - if (picker.options.calendarWeeks === true) { - row.append(''); + // Left and right logic + if (horizontal === 'auto') { + if (parent.width() < offset.left + widget.outerWidth() / 2 && + offset.left + widget.outerWidth() > $(window).width()) { + horizontal = 'right'; + } else { + horizontal = 'left'; } } - 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'; + + if (vertical === 'top') { + widget.addClass('top').removeClass('bottom'); + } else { + widget.addClass('bottom').removeClass('top'); } - if (prevMonth.isSame(moment({y: picker.date.year(), M: picker.date.month(), d: picker.date.date()}))) { - clsName += ' active'; + + if (horizontal === 'right') { + widget.addClass('pull-right'); + } else { + widget.removeClass('pull-right'); } - if (isInDisableDates(prevMonth, 'day') || !isInEnableDates(prevMonth)) { - clsName += ' disabled'; + + // find the first parent element that has a relative css positioning + if (parent.css('position') !== 'relative') { + parent = parent.parents().filter(function () { + return $(this).css('position') === 'relative'; + }).first(); } - if (picker.options.showToday === true) { - if (prevMonth.isSame(moment(), 'day')) { + + if (parent.length === 0) { + throw new Error('datetimepicker component should be placed within a relative positioned container'); + } + + widget.css({ + top: vertical === 'top' ? 'auto' : position.top + element.outerHeight(), + bottom: vertical === 'top' ? position.top + element.outerHeight() : 'auto', + left: horizontal === 'left' ? parent.css('padding-left') : 'auto', + right: horizontal === 'left' ? 'auto' : parent.width() - element.outerWidth() + }); + }, + + notifyEvent = function (e) { + if (e.type === 'dp.change' && ((e.date && e.date.isSame(e.oldDate)) || (!e.date && !e.oldDate))) { + return; + } + element.trigger(e); + }, + + 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(); + }, + + fillDow = function () { + var row = $(''), + currentDate = viewDate.clone().startOf('w'); + + if (options.calendarWeeks === true) { + row.append($(''); + 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 (picker.options.daysOfWeekDisabled) { - for (i = 0; i < picker.options.daysOfWeekDisabled.length; i++) { - if (prevMonth.day() === picker.options.daysOfWeekDisabled[i]) { - clsName += ' disabled'; - break; - } + if (currentDate.day() === 0 || currentDate.day() === 6) { + clsName += ' weekend'; } + row.append(''); + currentDate.add(1, 'd'); } - row.append(''); - currentDate = prevMonth.date(); - prevMonth.add(1, 'd'); + daysView.find('tbody').empty().append(html); - if (currentDate === prevMonth.date()) { - prevMonth.add(1, 'd'); + updateMonths(); + + updateYears(); + }, + + fillHours = function () { + var table = widget.find('.timepicker-hours table'), + currentHour = viewDate.clone().startOf('d'), + html = [], + row = $(''); + + if (viewDate.hour() > 11 && !use24Hours) { + currentHour.hour(12); } - } - 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'); - } - } - - 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'); - } - year -= 1; - for (i = -1; i < 11; i++) { - html += '' + year + ''; - year += 1; - } - 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++; + while (currentHour.isSame(viewDate, 'd') && (use24Hours || (viewDate.hour() < 12 && currentHour.hour() < 12) || viewDate.hour() > 11)) { + if (currentHour.hour() % 4 === 0) { + row = $(''); + html.push(row); } - html += ''; + row.append(''); + currentHour.add(1, 'h'); } - } - else { - current = 1; - for (i = 0; i < 3; i += 1) { - html += ''; - for (j = 0; j < 4; j += 1) { - html += ''; - current++; + table.empty().append(html); + }, + + fillMinutes = function () { + var table = widget.find('.timepicker-minutes table'), + currentMinute = viewDate.clone().startOf('h'), + html = [], + row = $(''), + step = options.stepping === 1 ? 5 : options.stepping; + + while (viewDate.isSame(currentMinute, 'h')) { + if (currentMinute.minute() % (step * 4) === 0) { + row = $(''); + html.push(row); } - html += ''; + row.append(''); + currentMinute.add(step, 'm'); } - } - table.html(html); - }, + table.empty().append(html); + }, - 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 += ''; + fillSeconds = function () { + var table = widget.find('.timepicker-seconds table'), + currentSecond = viewDate.clone().startOf('m'), + html = [], + row = $(''); + + while (viewDate.isSame(currentSecond, 'm')) { + if (currentSecond.second() % 20 === 0) { + row = $(''); + html.push(row); } + row.append(''); + currentSecond.add(5, 's'); } - html += ''; - } - 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; + 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')); } - html += ''; - } - table.html(html); - }, + timeComponents.filter('[data-time-component=hours]').text(date.format(use24Hours ? 'HH' : 'hh')); + timeComponents.filter('[data-time-component=minutes]').text(date.format('mm')); + timeComponents.filter('[data-time-component=seconds]').text(date.format('ss')); - fillTime = function () { - if (!picker.date) { - return; - } - 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; + fillHours(); + fillMinutes(); + fillSeconds(); + }, + + update = function () { + if (!widget) { + return; } - picker.widget.find('.timepicker [data-action=togglePeriod]').text(period); - } - 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())); - }, + fillDate(); + fillTime(); + }, - 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; - } + 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; } - } - }, - actions = { - incrementHours: function () { - checkDate('add', 'hours', 1); - }, + targetMoment = targetMoment.clone().locale(options.locale); - incrementMinutes: function () { - checkDate('add', 'minutes', picker.options.minuteStepping); - }, + if (options.stepping !== 1) { + targetMoment.minutes((Math.round(targetMoment.minutes() / options.stepping) * options.stepping) % 60).seconds(0); + } - incrementSeconds: function () { - checkDate('add', 'seconds', 1); - }, - - decrementHours: function () { - checkDate('subtract', 'hours', 1); - }, - - decrementMinutes: function () { - checkDate('subtract', 'minutes', picker.options.minuteStepping); - }, - - decrementSeconds: function () { - checkDate('subtract', 'seconds', 1); - }, - - togglePeriod: function () { - var hour = picker.date.hours(); - if (hour >= 12) { - hour -= 12; + 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 { - hour += 12; + if (!options.keepInvalid) { + input.val(unset ? '' : date.format(actualFormat)); + } + notifyEvent({ + type: 'dp.error', + date: targetMoment + }); } - picker.date.hours(hour); }, - showPicker: function () { - picker.widget.find('.timepicker > div:not(.timepicker-picker)').hide(); - picker.widget.find('.timepicker .timepicker-picker').show(); + 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; + } + return true; + }); + 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; }, - showHours: function () { - picker.widget.find('.timepicker .timepicker-picker').hide(); - picker.widget.find('.timepicker .timepicker-hours').show(); + clear = function () { + setValue(null); }, - showMinutes: function () { - picker.widget.find('.timepicker .timepicker-picker').hide(); - picker.widget.find('.timepicker .timepicker-minutes').show(); - }, + /******************************************************************************** + * + * Widget UI interaction functions + * + ********************************************************************************/ + actions = { + next: function () { + viewDate.add(datePickerModes[currentViewMode].navStep, datePickerModes[currentViewMode].navFnc); + fillDate(); + }, - showSeconds: function () { - picker.widget.find('.timepicker .timepicker-picker').hide(); - picker.widget.find('.timepicker .timepicker-seconds').show(); - }, + previous: function () { + viewDate.subtract(datePickerModes[currentViewMode].navStep, datePickerModes[currentViewMode].navFnc); + fillDate(); + }, - selectHour: function (e) { - var hour = parseInt($(e.target).text(), 10); - if (!picker.use24hours) { - if (picker.date.hours() >= 12) { - if (hour !== 12) { - hour += 12; + 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())); + if (!options.inline) { + hide(); } } else { - if (hour === 12) { - hour = 0; - } + showMode(-1); + fillDate(); } - } - picker.date.hours(hour); - actions.showPicker.call(picker); - }, + }, - selectMinute: function (e) { - picker.date.minutes(parseInt($(e.target).text(), 10)); - actions.showPicker.call(picker); - }, + selectYear: function (e) { + var year = parseInt($(e.target).text(), 10) || 0; + viewDate.year(year); + if (currentViewMode === minViewModeNumber) { + setValue(date.clone().year(viewDate.year())); + if (!options.inline) { + hide(); + } + } else { + showMode(-1); + fillDate(); + } + }, - selectSecond: function (e) { - picker.date.seconds(parseInt($(e.target).text(), 10)); - actions.showPicker.call(picker); - } - }, + 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 && !options.inline) { + hide(); + } + }, - 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; - }, + incrementHours: function () { + setValue(date.clone().add(1, 'h')); + }, - stopEvent = function (e) { - e.stopPropagation(); - e.preventDefault(); - }, + incrementMinutes: function () { + setValue(date.clone().add(options.stepping, 'm')); + }, - keydown = function (e) { - if (e.keyCode === 27) { // allow escape to hide picker - picker.hide(); - } - }, + incrementSeconds: function () { + setValue(date.clone().add(1, 's')); + }, - 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)) { - update(); - picker.setValue(newDate); - notifyChange(oldDate, e.type); - set(); - } - else { - picker.viewDate = oldDate; - picker.unset = true; - notifyChange(oldDate, e.type); - notifyError(newDate); - } - }, + decrementHours: function () { + setValue(date.clone().subtract(1, 'h')); + }, - showMode = function (dir) { - if (dir) { - picker.viewMode = Math.max(picker.minViewMode, Math.min(2, picker.viewMode + dir)); - } - picker.widget.find('.datepicker > div').hide().filter('.datepicker-' + dpGlobal.modes[picker.viewMode].clsName).show(); - }, + decrementMinutes: function () { + setValue(date.clone().subtract(options.stepping, 'm')); + }, - 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)'); + 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'); - $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 (expanded.collapse) { // if collapse plugin is available through bootstrap.js then use it + expanded.collapse('hide'); + closed.collapse('show'); + } else { // otherwise just toggle in class on the two views + expanded.removeClass('in'); + closed.addClass('in'); + } + 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; + } } } - }); - } - 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)); + 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: clear, + + today: function () { + setValue(moment()); + }, + + close: hide + }, + + doAction = function (e) { + if ($(e.currentTarget).is('.disabled')) { + return false; } - } - }, + actions[$(e.currentTarget).data('action')].apply(picker, arguments); + return false; + }, - attachDatePickerGlobalEvents = function () { - $(window).on( - 'resize.datetimepicker' + picker.id, $.proxy(place, this)); - if (!picker.isInput) { - $(document).on( - 'mousedown.datetimepicker' + picker.id, $.proxy(picker.hide, this)); - } - }, + 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); + } + }; - 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'); - } - if (picker.isInput) { - picker.element.off({ - 'focus': picker.show, + if (input.prop('disabled') || (!options.ignoreReadonly && input.prop('readonly')) || widget) { + return picker; + } + if (options.useCurrent && unset && ((input.is('input') && input.val().trim().length === 0) || options.inline)) { + currentMoment = moment(); + if (typeof options.useCurrent === 'string') { + currentMoment = useCurrentGranularity[options.useCurrent](currentMoment); + } + setValue(currentMoment); + } + + 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 (inputDate) { + if (moment.isMoment(inputDate) || inputDate instanceof Date) { + inputDate = moment(inputDate); + } else { + inputDate = moment(inputDate, parseFormats, options.useStrict); + } + inputDate.locale(options.locale); + return inputDate; + }, + + keydown = function (e) { + //if (e.keyCode === 27 && widget) { // allow escape to hide picker + // hide(); + // return false; + //} + //if (e.keyCode === 40 && !widget) { // allow down to show picker + // show(); + // e.preventDefault(); + //} + //return true; + + var handler = null, + index, + index2, + pressedKeys = [], + pressedModifiers = {}, + currentKey = e.which, + keyBindKeys, + allModifiersPressed, + pressed = 'p'; + + keyState[currentKey] = pressed; + + for (index in keyState) { + if (keyState.hasOwnProperty(index) && keyState[index] === pressed) { + pressedKeys.push(index); + if (parseInt(index, 10) !== currentKey) { + pressedModifiers[index] = true; + } + } + } + + for (index in options.keyBinds) { + if (options.keyBinds.hasOwnProperty(index) && typeof (options.keyBinds[index]) === 'function') { + keyBindKeys = index.split(' '); + if (keyBindKeys.length === pressedKeys.length && keyMap[currentKey] === keyBindKeys[keyBindKeys.length - 1]) { + allModifiersPressed = true; + for (index2 = keyBindKeys.length - 2; index2 >= 0; index2--) { + if (!(keyMap[keyBindKeys[index2]] in pressedModifiers)) { + allModifiersPressed = false; + break; + } + } + if (allModifiersPressed) { + handler = options.keyBinds[index]; + break; + } + } + } + } + + if (handler) { + handler.call(picker, widget); + e.stopPropagation(); + e.preventDefault(); + } + }, + + keyup = function (e) { + keyState[e.which] = 'r'; + e.stopPropagation(); + e.preventDefault(); + }, + + 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, - 'click': picker.show, - 'blur' : picker.hide + 'blur': options.debug ? '' : hide, + 'keydown': keydown, + 'keyup': keyup }); - } 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 (element.is('input')) { + input.on({ + 'focus': show + }); + } else if (component) { + component.on('click', toggle); + component.on('mousedown', false); } - } - }, + }, - detachDatePickerGlobalEvents = function () { - $(window).off('resize.datetimepicker' + picker.id); - if (!picker.isInput) { - $(document).off('mousedown.datetimepicker' + picker.id); - } - }, + detachDatePickerElementEvents = function () { + input.off({ + 'change': change, + 'blur': hide, + 'keydown': keydown, + 'keyup': keyup + }); - 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; + 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 (formatInput) { + var newinput = date.localeData().longDateFormat(formatInput) || formatInput; + return newinput.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g, function (formatInput2) { //temp fix for #740 + return date.localeData().longDateFormat(formatInput2) || formatInput2; + }); + }); + + + parseFormats = options.extraFormats ? options.extraFormats.slice() : []; + if (parseFormats.indexOf(format) < 0 && parseFormats.indexOf(actualFormat) < 0) { + parseFormats.push(actualFormat); } - return inFixed; - } else { - return false; - } - }, - 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(); - } - }, + use24Hours = (actualFormat.toLowerCase().indexOf('a') < 1 && actualFormat.indexOf('h') < 1); - 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); + if (isEnabled('y')) { + minViewModeNumber = 2; } - newDate.add(amount, unit); - } - else { - newDate = moment(picker.date).subtract(amount, unit); - } - if (isInDisableDates(moment(newDate.subtract(amount, unit))) || isInDisableDates(newDate)) { - notifyError(newDate.format(picker.format)); - return; - } - - if (direction === 'add') { - picker.date.add(amount, unit); - } - else { - picker.date.subtract(amount, unit); - } - picker.unset = false; - }, - - 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); - - if (timeUnit) { - maxDate = maxDate.endOf(timeUnit); - minDate = minDate.startOf(timeUnit); - } - - if (date.isAfter(maxDate) || date.isBefore(minDate)) { - return true; - } - if (picker.options.disabledDates === false) { - return false; - } - 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; - } - 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 (isEnabled('M')) { + minViewModeNumber = 1; } - if (dDate.isValid()) { - givenDatesIndexed[dDate.format('YYYY-MM-DD')] = true; - givenDatesCount++; + if (isEnabled('d')) { + minViewModeNumber = 0; } - } - if (givenDatesCount > 0) { - return givenDatesIndexed; - } - return false; - }, - padLeft = function (string) { - string = string.toString(); - if (string.length >= 2) { - return string; - } - return '0' + string; - }, + currentViewMode = Math.max(minViewModeNumber, currentViewMode); - getTemplate = function () { - var - headTemplate = - '' + - '' + - '' + - '' + - '', - contTemplate = - '', - template = '
' + - '
#' + weekdaysMin[i] + '' + weekdaysMin[0] + '' + weekdaysMin[i] + '
' + prevMonth.week() + '
').addClass('cw').text('#')); + } + + 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); + }, + + isInDisabledDates = function (testDate) { + return options.disabledDates[testDate.format('YYYY-MM-DD')] === true; + }, + + isInEnabledDates = function (testDate) { + return options.enabledDates[testDate.format('YYYY-MM-DD')] === true; + }, + + isValid = function (targetMoment, granularity) { + if (!targetMoment.isValid()) { + return false; + } + if (options.disabledDates && isInDisabledDates(targetMoment) && granularity !== 'M') { + return false; + } + if (options.enabledDates && !isInEnabledDates(targetMoment) && granularity !== 'M') { + return false; + } + 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) { //widget && widget.find('.datepicker-days').length > 0 + return false; + } + return true; + }, + + fillMonths = function () { + var spans = [], + monthsShort = viewDate.clone().startOf('y').hour(12); // hour is changed to avoid DST issues in some browsers + while (monthsShort.isSame(viewDate, 'y')) { + spans.push($('').attr('data-action', 'selectMonth').addClass('month').text(monthsShort.format('MMM'))); + monthsShort.add(1, 'M'); + } + widget.find('.datepicker-months td').empty().append(spans); + }, + + updateMonths = function () { + var monthsView = widget.find('.datepicker-months'), + monthsViewHeader = monthsView.find('th'), + months = monthsView.find('tbody').find('span'); + + monthsView.find('.disabled').removeClass('disabled'); + + if (!isValid(viewDate.clone().subtract(1, 'y'), 'y')) { + monthsViewHeader.eq(0).addClass('disabled'); + } + + 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'); + } + }); + }, + + updateYears = function () { + var yearsView = widget.find('.datepicker-years'), + yearsViewHeader = yearsView.find('th'), + startYear = viewDate.clone().subtract(5, 'y'), + endYear = viewDate.clone().add(6, 'y'), + html = ''; + + yearsView.find('.disabled').removeClass('disabled'); + + if (options.minDate && options.minDate.isAfter(startYear, 'y')) { + yearsViewHeader.eq(0).addClass('disabled'); + } + + yearsViewHeader.eq(1).text(startYear.year() + '-' + endYear.year()); + + if (options.maxDate && options.maxDate.isBefore(endYear, 'y')) { + yearsViewHeader.eq(2).addClass('disabled'); + } + + while (!startYear.isAfter(endYear, 'y')) { + html += '' + startYear.year() + ''; + startYear.add(1, 'y'); + } + + yearsView.find('td').html(html); + }, + + fillDate = function () { + var daysView = widget.find('.datepicker-days'), + daysViewHeader = daysView.find('th'), + currentDate, + html = [], + row, + clsName; + + if (!hasDate()) { + return; + } + + 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 = $('
' + currentDate.week() + '' + currentDate.date() + '' + prevMonth.date() + '
' + padLeft(current.toString()) + '
' + currentHour.format(use24Hours ? 'HH' : 'hh') + '
' + padLeft(current.toString()) + '
' + currentMinute.format('mm') + '
' + padLeft(current.toString()) + '
' + currentSecond.format('ss') + '
' + padLeft(current.toString()) + '
' + headTemplate + '
' + - '' + - '
' + - '' + headTemplate + contTemplate + '
' + - '
' + - '
' + - '' + headTemplate + contTemplate + '
' + - '
', - ret = ''; - if (picker.options.pickDate && picker.options.pickTime) { - ret = '
'; - return ret; - } - 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 - } - ] - }, - - tpGlobal = { - hourTemplate: '', - minuteTemplate: '', - secondTemplate: '' - }; - - 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 ? - '
' : '') - ); - }; + }; + /******************************************************************************** + * + * 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 () { - detachDatePickerEvents(); - detachDatePickerGlobalEvents(); - picker.widget.remove(); - picker.element.removeData('DateTimePicker'); - if (picker.component) { - picker.component.removeData('DateTimePicker'); - } + hide(); + detachDatePickerElementEvents(); + element.removeData('DateTimePicker'); + element.removeData('date'); }; - 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 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 (picker.widget.hasClass('picker-open')) { - picker.widget.hide(); - picker.widget.removeClass('picker-open'); - } - else { - picker.widget.show(); - picker.widget.addClass('picker-open'); - } - 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); - } - }; + picker.toggle = toggle; + + picker.show = show; + + picker.hide = hide; picker.disable = function () { - var input = getPickerInput(); - if (input.prop('disabled')) { - return; + hide(); + if (component && component.hasClass('btn')) { + component.addClass('disabled'); } input.prop('disabled', true); - detachDatePickerEvents(); + return picker; }; picker.enable = function () { - var input = getPickerInput(); - if (!input.prop('disabled')) { - return; + if (component && component.hasClass('btn')) { + component.removeClass('disabled'); } input.prop('disabled', false); - attachDatePickerEvents(); + 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.ignoreReadonly = function (ignoreReadonly) { + if (arguments.length === 0) { + return options.ignoreReadonly; + } + if (typeof ignoreReadonly !== 'boolean') { + throw new TypeError('ignoreReadonly () expects a boolean parameter'); + } + options.ignoreReadonly = ignoreReadonly; + return picker; + }; + + picker.options = function (newOptions) { + if (arguments.length === 0) { + return $.extend(true, {}, options); + } + + if (!(newOptions instanceof Object)) { + throw new TypeError('options() options parameter should be an object'); + } + $.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!'); + } + }); + return picker; + }; + + picker.date = function (newDate) { + if (arguments.length === 0) { + if (unset) { + return null; + } + return date.clone(); + } + + 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]'); + } + + setValue(newDate === null ? null : parseInputDate(newDate)); + return picker; + }; + + picker.format = function (newFormat) { + if (arguments.length === 0) { + return options.format; + } + + if ((typeof newFormat !== 'string') && ((typeof newFormat !== 'boolean') || (newFormat !== false))) { + throw new TypeError('format() expects a sting or boolean:false parameter ' + newFormat); + } + + options.format = newFormat; + if (actualFormat) { + initFormatting(); // reinit formatting + } + return picker; + }; + + picker.dayViewHeaderFormat = function (newFormat) { + if (arguments.length === 0) { + return options.dayViewHeaderFormat; + } + + if (typeof newFormat !== 'string') { + throw new TypeError('dayViewHeaderFormat() expects a string parameter'); + } + + options.dayViewHeaderFormat = newFormat; + return picker; + }; + + picker.extraFormats = function (formats) { + if (arguments.length === 0) { + return options.extraFormats; + } + + if (formats !== false && !(formats instanceof Array)) { + throw new TypeError('extraFormats() expects an array or false parameter'); + } + + options.extraFormats = formats; + if (parseFormats) { + initFormatting(); // reinit formatting + } + return picker; + }; + + picker.disabledDates = function (dates) { + if (arguments.length === 0) { + return (options.disabledDates ? $.extend({}, options.disabledDates) : options.disabledDates); + } + + 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; + }; + + picker.enabledDates = function (dates) { + if (arguments.length === 0) { + return (options.enabledDates ? $.extend({}, options.enabledDates) : options.enabledDates); + } + + 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; + }; + + picker.daysOfWeekDisabled = function (daysOfWeekDisabled) { + if (arguments.length === 0) { + return options.daysOfWeekDisabled.splice(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; + } + if (previousValue.indexOf(currentValue) === -1) { + previousValue.push(currentValue); + } + return previousValue; + }, []).sort(); + update(); + return picker; + }; + + picker.maxDate = function (maxDate) { + if (arguments.length === 0) { + return options.maxDate ? options.maxDate.clone() : options.maxDate; + } + + if ((typeof maxDate === 'boolean') && maxDate === false) { + options.maxDate = false; + update(); + return picker; + } + + if (typeof maxDate === 'string') { + if (maxDate === 'now' || maxDate === 'moment') { + maxDate = moment(); } } - picker.widget.hide(); - picker.widget.removeClass('picker-open'); - picker.viewMode = picker.startViewMode; + + var parsedDate = parseInputDate(maxDate); + + if (!parsedDate.isValid()) { + throw new TypeError('maxDate() Could not parse date parameter: ' + maxDate); + } + 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(maxDate)) { + setValue(options.maxDate); + } + if (viewDate.isAfter(parsedDate)) { + viewDate = parsedDate.clone(); + } + update(); + return picker; + }; + + picker.minDate = function (minDate) { + if (arguments.length === 0) { + return options.minDate ? options.minDate.clone() : options.minDate; + } + + if ((typeof minDate === 'boolean') && minDate === false) { + options.minDate = false; + update(); + return picker; + } + + if (typeof minDate === 'string') { + if (minDate === 'now' || minDate === 'moment') { + minDate = moment(); + } + } + + var parsedDate = parseInputDate(minDate); + + if (!parsedDate.isValid()) { + throw new TypeError('minDate() Could not parse date parameter: ' + minDate); + } + 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(minDate)) { + setValue(options.minDate); + } + if (viewDate.isBefore(parsedDate)) { + viewDate = parsedDate.clone(); + } + update(); + return picker; + }; + + picker.defaultDate = function (defaultDate) { + if (arguments.length === 0) { + return options.defaultDate ? options.defaultDate.clone() : options.defaultDate; + } + if (!defaultDate) { + options.defaultDate = false; + return picker; + } + + if (typeof defaultDate === 'string') { + if (defaultDate === 'now' || defaultDate === 'moment') { + defaultDate = moment(); + } + } + + 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'); + } + + options.defaultDate = parsedDate; + + if (options.defaultDate && input.val().trim() === '' && input.attr('placeholder') === undefined) { + setValue(options.defaultDate); + } + return picker; + }; + + picker.locale = function (locale) { + if (arguments.length === 0) { + return options.locale; + } + + if (!moment.localeData(locale)) { + throw new TypeError('locale() locale ' + locale + ' is not loaded from moment locales!'); + } + + options.locale = locale; + date.locale(options.locale); + viewDate.locale(options.locale); + + if (actualFormat) { + initFormatting(); // reinit formatting + } + if (widget) { + hide(); + show(); + } + return picker; + }; + + picker.stepping = function (stepping) { + if (arguments.length === 0) { + return options.stepping; + } + + stepping = parseInt(stepping, 10); + if (isNaN(stepping) || stepping < 1) { + stepping = 1; + } + options.stepping = stepping; + return picker; + }; + + picker.useCurrent = function (useCurrent) { + var useCurrentOptions = ['year', 'month', 'day', 'hour', 'minute']; + if (arguments.length === 0) { + return options.useCurrent; + } + + if ((typeof useCurrent !== 'boolean') && (typeof useCurrent !== 'string')) { + throw new TypeError('useCurrent() expects a boolean or string parameter'); + } + if (typeof useCurrent === 'string' && useCurrentOptions.indexOf(useCurrent.toLowerCase()) === -1) { + throw new TypeError('useCurrent() expects a string parameter of ' + useCurrentOptions.join(', ')); + } + options.useCurrent = useCurrent; + return picker; + }; + + picker.collapse = function (collapse) { + if (arguments.length === 0) { + return options.collapse; + } + + if (typeof collapse !== 'boolean') { + throw new TypeError('collapse() expects a boolean parameter'); + } + if (options.collapse === collapse) { + return picker; + } + options.collapse = collapse; + if (widget) { + hide(); + show(); + } + return picker; + }; + + picker.icons = function (icons) { + if (arguments.length === 0) { + return $.extend({}, options.icons); + } + + if (!(icons instanceof Object)) { + throw new TypeError('icons() expects parameter to be an Object'); + } + $.extend(options.icons, icons); + if (widget) { + hide(); + show(); + } + return picker; + }; + + picker.useStrict = function (useStrict) { + if (arguments.length === 0) { + return options.useStrict; + } + + if (typeof useStrict !== 'boolean') { + throw new TypeError('useStrict() expects a boolean parameter'); + } + options.useStrict = useStrict; + return picker; + }; + + picker.sideBySide = function (sideBySide) { + if (arguments.length === 0) { + return options.sideBySide; + } + + if (typeof sideBySide !== 'boolean') { + throw new TypeError('sideBySide() expects a boolean parameter'); + } + options.sideBySide = sideBySide; + if (widget) { + hide(); + show(); + } + return picker; + }; + + picker.viewMode = function (viewMode) { + if (arguments.length === 0) { + return options.viewMode; + } + + if (typeof viewMode !== 'string') { + throw new TypeError('viewMode() expects a string parameter'); + } + + if (viewModes.indexOf(viewMode) === -1) { + throw new TypeError('viewMode() parameter must be one of (' + viewModes.join(', ') + ') value'); + } + + options.viewMode = viewMode; + currentViewMode = Math.max(viewModes.indexOf(viewMode), minViewModeNumber); + showMode(); - picker.element.trigger({ - type: 'dp.hide', - date: moment(picker.date) - }); - detachDatePickerGlobalEvents(); + return picker; }; - picker.setValue = function (newDate) { - moment.locale(picker.options.language); - if (!newDate) { - picker.unset = true; - set(); + picker.toolbarPlacement = function (toolbarPlacement) { + if (arguments.length === 0) { + return options.toolbarPlacement; + } + + if (typeof toolbarPlacement !== 'string') { + throw new TypeError('toolbarPlacement() expects a string parameter'); + } + if (toolbarPlacements.indexOf(toolbarPlacement) === -1) { + throw new TypeError('toolbarPlacement() parameter must be one of (' + toolbarPlacements.join(', ') + ') value'); + } + options.toolbarPlacement = toolbarPlacement; + + if (widget) { + hide(); + show(); + } + return picker; + }; + + picker.widgetPositioning = function (widgetPositioning) { + if (arguments.length === 0) { + return $.extend({}, options.widgetPositioning); + } + + 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.calendarWeeks = function (calendarWeeks) { + if (arguments.length === 0) { + return options.calendarWeeks; + } + + if (typeof calendarWeeks !== 'boolean') { + throw new TypeError('calendarWeeks() expects parameter to be a boolean value'); + } + + options.calendarWeeks = calendarWeeks; + update(); + return picker; + }; + + picker.showTodayButton = function (showTodayButton) { + if (arguments.length === 0) { + return options.showTodayButton; + } + + if (typeof showTodayButton !== 'boolean') { + throw new TypeError('showTodayButton() expects a boolean parameter'); + } + + options.showTodayButton = showTodayButton; + if (widget) { + hide(); + show(); + } + return picker; + }; + + picker.showClear = function (showClear) { + if (arguments.length === 0) { + return options.showClear; + } + + if (typeof showClear !== 'boolean') { + throw new TypeError('showClear() expects a boolean parameter'); + } + + options.showClear = showClear; + if (widget) { + hide(); + show(); + } + return picker; + }; + + picker.widgetParent = function (widgetParent) { + if (arguments.length === 0) { + return options.widgetParent; + } + + if (typeof widgetParent === 'string') { + widgetParent = $(widgetParent); + } + + if (widgetParent !== null && (typeof widgetParent !== 'string' && !(widgetParent instanceof $))) { + throw new TypeError('widgetParent() expects a string or a jQuery object parameter'); + } + + options.widgetParent = widgetParent; + if (widget) { + hide(); + show(); + } + return picker; + }; + + picker.keepOpen = function (keepOpen) { + if (arguments.length === 0) { + return options.keepOpen; + } + + if (typeof keepOpen !== 'boolean') { + throw new TypeError('keepOpen() expects a boolean parameter'); + } + + options.keepOpen = keepOpen; + return picker; + }; + + picker.inline = function (inline) { + if (arguments.length === 0) { + return options.inline; + } + + if (typeof inline !== 'boolean') { + throw new TypeError('inline() expects a boolean parameter'); + } + + options.inline = inline; + return picker; + }; + + picker.clear = function () { + clear(); + return picker; + }; + + picker.keyBinds = function (keyBinds) { + options.keyBinds = keyBinds; + return picker; + }; + + picker.debug = function (debug) { + if (typeof debug !== 'boolean') { + throw new TypeError('debug() expects a boolean parameter'); + } + + options.debug = debug; + return picker; + }; + + picker.showClose = function (showClose) { + if (arguments.length === 0) { + return options.showClose; + } + + if (typeof showClose !== 'boolean') { + throw new TypeError('showClose() expects a boolean parameter'); + } + + options.showClose = showClose; + return picker; + }; + + picker.keepInvalid = function (keepInvalid) { + if (arguments.length === 0) { + return options.keepInvalid; + } + + if (typeof keepInvalid !== 'boolean') { + throw new TypeError('keepInvalid() expects a boolean parameter'); + } + options.keepInvalid = keepInvalid; + return picker; + }; + + picker.datepickerInput = function (datepickerInput) { + if (arguments.length === 0) { + return options.datepickerInput; + } + + if (typeof datepickerInput !== 'string') { + throw new TypeError('datepickerInput() expects a string parameter'); + } + + options.datepickerInput = datepickerInput; + return picker; + }; + + // initializing element and component attributes + if (element.is('input')) { + input = element; + } else { + input = element.find(options.datepickerInput); + if (input.size() === 0) { + input = element.find('input'); + } else if (!input.is('input')) { + throw new Error('CSS class "' + options.datepickerInput + '" cannot be applied to non input element'); + } + } + + 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.unset = false; + component = element.find('.datepickerbutton'); } - if (!moment.isMoment(newDate)) { - newDate = (newDate instanceof Date) ? moment(newDate) : moment(newDate, picker.format, picker.options.useStrict); - } else { - newDate = newDate.locale(picker.options.language); - } - if (newDate.isValid()) { - picker.date = newDate; - set(); - picker.viewDate = moment({y: picker.date.year(), M: picker.date.month()}); - fillDate(); - fillTime(); - } - else { - notifyError(newDate); - } - }; + } - picker.getDate = function () { - if (picker.unset) { - return null; - } - return moment(picker.date); - }; + if (!options.inline && !input.is('input')) { + throw new Error('Could not initialize DateTimePicker without an input element'); + } - picker.setDate = function (date) { - var oldDate = moment(picker.date); - if (!date) { - picker.setValue(null); - } else { - picker.setValue(date); - } - notifyChange(oldDate, 'function'); - }; + $.extend(true, options, dataToOptions()); - picker.setDisabledDates = function (dates) { - picker.options.disabledDates = indexGivenDates(dates); - if (picker.viewDate) { - update(); - } - }; + picker.options(options); - picker.setEnabledDates = function (dates) { - picker.options.enabledDates = indexGivenDates(dates); - if (picker.viewDate) { - update(); - } - }; + initFormatting(); - picker.setMaxDate = function (date) { - if (date === undefined) { - return; - } - if (moment.isMoment(date) || date instanceof Date) { - picker.options.maxDate = moment(date); - } else { - picker.options.maxDate = moment(date, picker.format, picker.options.useStrict); - } - if (picker.viewDate) { - update(); - } - }; + attachDatePickerElementEvents(); - picker.setMinDate = function (date) { - if (date === undefined) { - return; - } - if (moment.isMoment(date) || date instanceof Date) { - picker.options.minDate = moment(date); - } else { - picker.options.minDate = moment(date, picker.format, picker.options.useStrict); - } - if (picker.viewDate) { - update(); - } - }; - - init(); + if (input.prop('disabled')) { + picker.disable(); + } + if (input.is('input') && input.val().trim().length !== 0) { + setValue(parseInputDate(input.val().trim())); + } + else if (options.defaultDate && input.attr('placeholder') === undefined) { + setValue(options.defaultDate); + } + if (options.inline) { + show(); + } + 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', + close: 'glyphicon glyphicon-remove' + }, useStrict: false, - direction: 'auto', sideBySide: false, daysOfWeekDisabled: [], - widgetParent: false + calendarWeeks: false, + viewMode: 'days', + toolbarPlacement: 'default', + showTodayButton: false, + showClear: false, + showClose: false, + widgetPositioning: { + horizontal: 'auto', + vertical: 'auto' + }, + widgetParent: null, + ignoreReadonly: false, + keepOpen: false, + inline: false, + keepInvalid: false, + datepickerInput: '.datepickerinput', + keyBinds: { + up: function (widget) { + if (!widget) { + return; + } + var d = this.date() || moment(); + if (widget.find('.datepicker').is(':visible')) { + this.date(d.clone().subtract(7, 'd')); + } else { + this.date(d.clone().add(1, 'm')); + } + }, + down: function (widget) { + if (!widget) { + this.show(); + return; + } + var d = this.date() || moment(); + if (widget.find('.datepicker').is(':visible')) { + this.date(d.clone().add(7, 'd')); + } else { + this.date(d.clone().subtract(1, 'm')); + } + }, + 'control up': function (widget) { + if (!widget) { + return; + } + var d = this.date() || moment(); + if (widget.find('.datepicker').is(':visible')) { + this.date(d.clone().subtract(1, 'y')); + } else { + this.date(d.clone().add(1, 'h')); + } + }, + 'control down': function (widget) { + if (!widget) { + return; + } + var d = this.date() || moment(); + if (widget.find('.datepicker').is(':visible')) { + this.date(d.clone().add(1, 'y')); + } else { + this.date(d.clone().subtract(1, 'h')); + } + }, + left: function (widget) { + if (!widget) { + return; + } + var d = this.date() || moment(); + if (widget.find('.datepicker').is(':visible')) { + this.date(d.clone().subtract(1, 'd')); + } + }, + right: function (widget) { + if (!widget) { + return; + } + var d = this.date() || moment(); + if (widget.find('.datepicker').is(':visible')) { + this.date(d.clone().add(1, 'd')); + } + }, + pageUp: function (widget) { + if (!widget) { + return; + } + var d = this.date() || moment(); + if (widget.find('.datepicker').is(':visible')) { + this.date(d.clone().subtract(1, 'M')); + } + }, + pageDown: function (widget) { + if (!widget) { + return; + } + var d = this.date() || moment(); + if (widget.find('.datepicker').is(':visible')) { + this.date(d.clone().add(1, 'M')); + } + }, + enter: function () { + this.hide(); + }, + escape: function () { + this.hide(); + }, + //tab: function (widget) { //this break the flow of the form. disabling for now + // var toggle = widget.find('.picker-switch a[data-action="togglePicker"]'); + // if(toggle.length > 0) toggle.click(); + //}, + 'control space': function (widget) { + if (widget.find('.timepicker').is(':visible')) { + widget.find('.btn[data-action="togglePeriod"]').click(); + } + }, + t: function () { + this.date(moment()); + }, + 'delete': function () { + this.clear(); + } + }, + debug: false }; })); diff --git a/html/js/datetime/src/less/_bootstrap-datetimepicker.less b/html/js/datetime/src/less/_bootstrap-datetimepicker.less new file mode 100644 index 000000000..64d9a70e7 --- /dev/null +++ b/html/js/datetime/src/less/_bootstrap-datetimepicker.less @@ -0,0 +1,343 @@ +/*! + * Datetimepicker for Bootstrap 3 + * ! version : 4.7.14 + * https://github.com/Eonasdan/bootstrap-datetimepicker/ + */ +@bs-datetimepicker-timepicker-font-size: 1.2em; +@bs-datetimepicker-active-bg: @btn-primary-bg; +@bs-datetimepicker-active-color: @btn-primary-color; +@bs-datetimepicker-border-radius: @border-radius-base; +@bs-datetimepicker-btn-hover-bg: @gray-lighter; +@bs-datetimepicker-disabled-color: @gray-light; +@bs-datetimepicker-alternate-color: @gray-light; +@bs-datetimepicker-secondary-border-color: #ccc; +@bs-datetimepicker-secondary-border-color-rgba: rgba(0, 0, 0, 0.2); +@bs-datetimepicker-primary-border-color: white; +@bs-datetimepicker-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); + +.bootstrap-datetimepicker-widget { + list-style: none; + + &.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 @bs-datetimepicker-secondary-border-color; + border-bottom-color: @bs-datetimepicker-secondary-border-color-rgba; + top: -7px; + left: 7px; + } + + &:after { + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid @bs-datetimepicker-primary-border-color; + top: -6px; + left: 8px; + } + } + + &.top { + &:before { + border-left: 7px solid transparent; + border-right: 7px solid transparent; + border-top: 7px solid @bs-datetimepicker-secondary-border-color; + border-top-color: @bs-datetimepicker-secondary-border-color-rgba; + bottom: -7px; + left: 6px; + } + + &:after { + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-top: 6px solid @bs-datetimepicker-primary-border-color; + 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: @bs-datetimepicker-timepicker-font-size; + 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"; + } + + .btn[data-action="clear"]::after { + .sr-only(); + content: "Clear the picker"; + } + + .btn[data-action="today"]::after { + .sr-only(); + content: "Set the date to today"; + } + + .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: @bs-datetimepicker-border-radius; + } + + & th { + height: 20px; + line-height: 20px; + width: 20px; + + &.picker-switch { + width: 145px; + } + + &.disabled, + &.disabled:hover { + background: none; + color: @bs-datetimepicker-disabled-color; + 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: @bs-datetimepicker-btn-hover-bg; + } + } + + & td { + height: 54px; + line-height: 54px; + width: 54px; + + &.cw { + font-size: .8em; + height: 20px; + line-height: 20px; + color: @bs-datetimepicker-alternate-color; + } + + &.day { + height: 20px; + line-height: 20px; + width: 20px; + } + + &.day:hover, + &.hour:hover, + &.minute:hover, + &.second:hover { + background: @bs-datetimepicker-btn-hover-bg; + cursor: pointer; + } + + &.old, + &.new { + color: @bs-datetimepicker-alternate-color; + } + + &.today { + position: relative; + + &:before { + content: ''; + display: inline-block; + border: 0 0 7px 7px solid transparent; + border-bottom-color: @bs-datetimepicker-active-bg; + border-top-color: @bs-datetimepicker-secondary-border-color-rgba; + position: absolute; + bottom: 4px; + right: 4px; + } + } + + &.active, + &.active:hover { + background-color: @bs-datetimepicker-active-bg; + color: @bs-datetimepicker-active-color; + text-shadow: @bs-datetimepicker-text-shadow; + } + + &.active.today:before { + border-bottom-color: #fff; + } + + &.disabled, + &.disabled:hover { + background: none; + color: @bs-datetimepicker-disabled-color; + cursor: not-allowed; + } + + span { + display: inline-block; + width: 54px; + height: 54px; + line-height: 54px; + margin: 2px 1.5px; + cursor: pointer; + border-radius: @bs-datetimepicker-border-radius; + + &:hover { + background: @bs-datetimepicker-btn-hover-bg; + } + + &.active { + background-color: @bs-datetimepicker-active-bg; + color: @bs-datetimepicker-active-color; + text-shadow: @bs-datetimepicker-text-shadow; + } + + &.old { + color: @bs-datetimepicker-alternate-color; + } + + &.disabled, + &.disabled:hover { + background: none; + color: @bs-datetimepicker-disabled-color; + cursor: not-allowed; + } + } + } + } + + &.usetwentyfour { + td.hour { + height: 27px; + line-height: 27px; + } + } +} + +.input-group.date { + & .input-group-addon { + cursor: pointer; + } +} diff --git a/html/js/datetime/src/less/bootstrap-datetimepicker-build.less b/html/js/datetime/src/less/bootstrap-datetimepicker-build.less index 4a1737015..76dd98a65 100644 --- a/html/js/datetime/src/less/bootstrap-datetimepicker-build.less +++ b/html/js/datetime/src/less/bootstrap-datetimepicker-build.less @@ -1,5 +1,17 @@ -// Import boostrap variables including default color palette and fonts +// Import bootstrap variables including default color palette and fonts @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; +} diff --git a/html/js/datetime/src/less/bootstrap-datetimepicker.less b/html/js/datetime/src/less/bootstrap-datetimepicker.less deleted file mode 100755 index 14eb9da54..000000000 --- a/html/js/datetime/src/less/bootstrap-datetimepicker.less +++ /dev/null @@ -1,294 +0,0 @@ -/*! - * Datetimepicker for Bootstrap v3 -//! version : 3.1.3 - * 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: @border-radius-base; - - &.timepicker-sbs { - width: 600px; - } - - &.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; - } - - &:after { - content: ''; - display: inline-block; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-bottom: 6px solid white; - position: absolute; - top: -6px; - left: 8px; - } - } - - &.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; - } - - &:after { - content: ''; - display: inline-block; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-top: 6px solid white; - position: absolute; - bottom: -6px; - left: 7px; - } - } - - & .dow { - width: 14.2857%; - } - - &.pull-right { - &:before { - left: auto; - right: 6px; - } - - &:after { - left: auto; - right: 7px; - } - } - - >ul { - list-style-type: none; - 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; - } - - table[data-hour-format="12"] .separator { - width: 4px; - padding: 0; - margin: 0; - } - - .datepicker > div { - display: none; - } - - .picker-switch { - text-align: center; - } - - table { - width: 100%; - margin: 0; - } - - td, - th { - text-align: center; - border-radius: @border-radius-base; - } - - td { - height: 54px; - line-height: 54px; - width: 54px; - - &.cw - { - font-size: 10px; - 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; - } - } - } - - th { - height: 20px; - line-height: 20px; - width: 20px; - - &.picker-switch { - width: 145px; - } - - &.next, - &.prev { - font-size: @font-size-base * 1.5; - } - - &.disabled, - &.disabled:hover { - background: none; - color: @gray-light; - cursor: not-allowed; - } - } - - thead tr:first-child th { - cursor: pointer; - - &:hover { - background: @gray-lighter; - } - } -} - -.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; - } - - &: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; - } -} diff --git a/html/js/datetime/src/nuget/Bootstrap.v3.Datetimepicker.CSS.nuspec b/html/js/datetime/src/nuget/Bootstrap.v3.Datetimepicker.CSS.nuspec index 4192e1eb7..8f2add7ef 100644 --- a/html/js/datetime/src/nuget/Bootstrap.v3.Datetimepicker.CSS.nuspec +++ b/html/js/datetime/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/html/js/datetime/src/nuget/Bootstrap.v3.Datetimepicker.nuspec b/html/js/datetime/src/nuget/Bootstrap.v3.Datetimepicker.nuspec index 267ec06a4..2cd9551a0 100644 --- a/html/js/datetime/src/nuget/Bootstrap.v3.Datetimepicker.nuspec +++ b/html/js/datetime/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/html/js/datetime/src/nuget/install.ps1 b/html/js/datetime/src/nuget/install.ps1 index b0443b27c..e3220106e 100644 --- a/html/js/datetime/src/nuget/install.ps1 +++ b/html/js/datetime/src/nuget/install.ps1 @@ -1,2 +1,2 @@ # install.ps1 -$DTE.ItemOperations.Navigate("https://github.com/Eonasdan/bootstrap-datetimepicker#change-log", $DTE.vsNavigateOptions.vsNavigateOptionsNewWindow) +$DTE.ItemOperations.Navigate("http://eonasdan.github.io/bootstrap-datetimepicker/", $DTE.vsNavigateOptions.vsNavigateOptionsNewWindow) diff --git a/html/js/datetime/test/publicApiSpec.js b/html/js/datetime/test/publicApiSpec.js new file mode 100644 index 000000000..c9b7a5034 --- /dev/null +++ b/html/js/datetime/test/publicApiSpec.js @@ -0,0 +1,700 @@ +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('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('ignoreReadonly() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.ignoreReadonly).toBeDefined(); + }); + }); + }); + + 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(); + }); + }); + }); + + describe('dayViewHeaderFormat() function', function () { + describe('typechecking', function () { + it('does not accept a false value', function () { + expect(function () { + dtp.dayViewHeaderFormat(false); + }).toThrow(); + }); + + it('accepts a string', function () { + expect(function () { + dtp.dayViewHeaderFormat('YYYY-MM-DD'); + }).not.toThrow(); + }); + + it('does not accept undefined', function () { + expect(function () { + dtp.dayViewHeaderFormat(undefined); + }).toThrow(); + }); + + it('does not accept true', function () { + expect(function () { + dtp.dayViewHeaderFormat(true); + }).toThrow(); + }); + + it('does not accept a generic Object', function () { + expect(function () { + dtp.dayViewHeaderFormat({}); + }).toThrow(); + }); + }); + + describe('functionality', function () { + it('expects dayViewHeaderFormat to be default of MMMM YYYY', function () { + expect(dtp.dayViewHeaderFormat()).toBe('MMMM YYYY'); + }); + + it('sets the dayViewHeaderFormat correctly', function () { + dtp.dayViewHeaderFormat('MM YY'); + expect(dtp.dayViewHeaderFormat()).toBe('MM YY'); + }); + }); + }); + + describe('extraFormats() function', function () { + describe('typechecking', function () { + it('accepts a false value', function () { + expect(function () { + dtp.extraFormats(false); + }).not.toThrow(); + }); + + it('does not accept a string', function () { + expect(function () { + dtp.extraFormats('YYYY-MM-DD'); + }).toThrow(); + }); + + it('does not accept undefined', function () { + expect(function () { + dtp.extraFormats(undefined); + }).toThrow(); + }); + + it('does not accept true', function () { + expect(function () { + dtp.extraFormats(true); + }).toThrow(); + }); + + it('accepts an Array', function () { + expect(function () { + dtp.extraFormats(['YYYY-MM-DD']); + }).not.toThrow(); + }); + }); + + describe('functionality', function () { + it('returns no extraFormats before extraFormats is set', function () { + expect(dtp.extraFormats()).toBe(false); + }); + + it('sets the extraFormats correctly', function () { + dtp.extraFormats(['YYYY-MM-DD']); + expect(dtp.extraFormats()[0]).toBe('YYYY-MM-DD'); + }); + }); + }); + + describe('toolbarPlacement() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.toolbarPlacement).toBeDefined(); + }); + }); + describe('check type and parameter validity', function () { + it('does not accept a false value', function () { + expect(function () { + dtp.dayViewHeaderFormat(false); + }).toThrow(); + }); + it('does not accept a false value', function () { + expect(function () { + dtp.dayViewHeaderFormat(false); + }).toThrow(); + }); + it('accepts a string', function () { + var toolbarPlacementOptions = ['default', 'top', 'bottom']; + + toolbarPlacementOptions.forEach(function (value) { + expect(function () { + dtp.toolbarPlacement(value); + }).not.toThrow(); + }); + + expect(function () { + dtp.toolbarPlacement('test'); + }).toThrow(); + expect(function () { + dtp.toolbarPlacement({}); + }).toThrow(); + }); + }); + }); + + describe('widgetParent() function', function () { + describe('typechecking', function () { + it('accepts a null', function () { + expect(function () { + dtp.widgetParent(null); + }).not.toThrow(); + }); + + it('accepts a string', function () { + expect(function () { + dtp.widgetParent('testDiv'); + }).not.toThrow(); + }); + + it('accepts a jquery object', function () { + expect(function () { + dtp.widgetParent($('#testDiv')); + }).not.toThrow(); + }); + + it('does not accept undefined', function () { + expect(function () { + dtp.widgetParent(undefined); + }).toThrow(); + }); + + it('does not accept a number', function () { + expect(function () { + dtp.widgetParent(0); + }).toThrow(); + }); + + it('does not accept a generic Object', function () { + expect(function () { + dtp.widgetParent({}); + }).toThrow(); + }); + + it('does not accept a boolean', function () { + expect(function () { + dtp.widgetParent(false); + }).toThrow(); + }); + }); + }); + + describe('keepOpen() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.keepOpen).toBeDefined(); + }); + }); + }); + + describe('inline() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.inline).toBeDefined(); + }); + }); + }); + + describe('clear() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.clear).toBeDefined(); + }); + }); + }); + + describe('keyBinds() function', function () { + describe('existence', function () { + it('is defined', function () { + expect(dtp.keyBinds).toBeDefined(); + }); + }); + }); +});