diff --git a/common/css/timepicker.css b/common/css/timepicker.css index 8166d4da0e9..7cac8b02dcb 100644 --- a/common/css/timepicker.css +++ b/common/css/timepicker.css @@ -1,91 +1,423 @@ -/* - Datepicker for Bootstrap - Copyright 2012 Stefan Petre - Licensed under the Apache License v2.0 - http://www.apache.org/licenses/LICENSE-2.0 -*/ -input[type="date"] { -webkit-appearance: none; } .datepicker { top: 0; left: 0; padding: 4px; margin-top: 1px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; /*.dow { border-top: 1px solid #ddd !important; }*/ } .datepicker: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, 0.2); position: absolute; top: -7px; left: 6px; } .datepicker:after { content: ''; display: inline-block; border-left: 6px solid transparent; border-right: 6px solid transparent; border-bottom: 6px solid #ffffff; position: absolute; top: -6px; left: 7px; } .datepicker > div { display: none; } .datepicker table { width: 100%; margin: 0; } .datepicker td, .datepicker th { text-align: center; width: 20px; height: 20px; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .datepicker td.day:hover { background: #eeeeee; cursor: pointer; } .datepicker td.old, .datepicker td.new { color: #999999; } .datepicker td.active, .datepicker td.active:hover { background-color: #006dcc; background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-image: -ms-linear-gradient(top, #0088cc, #0044cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); background-image: linear-gradient(top, #0088cc, #0044cc); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); color: #fff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .datepicker td.active:hover, .datepicker td.active:hover:hover, .datepicker td.active:active, .datepicker td.active:hover:active, .datepicker td.active.active, .datepicker td.active:hover.active, .datepicker td.active.disabled, .datepicker td.active:hover.disabled, .datepicker td.active[disabled], .datepicker td.active:hover[disabled] { background-color: #0044cc; } .datepicker td.active:active, .datepicker td.active:hover:active, .datepicker td.active.active, .datepicker td.active:hover.active { background-color: #003399 \9; } .datepicker td span { display: block; width: 47px; height: 54px; line-height: 54px; float: left; margin: 2px; cursor: pointer; -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; } .datepicker td span:hover { background: #eeeeee; } .datepicker td span.active { background-color: #006dcc; background-image: -moz-linear-gradient(top, #0088cc, #0044cc); background-image: -ms-linear-gradient(top, #0088cc, #0044cc); background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); background-image: -o-linear-gradient(top, #0088cc, #0044cc); background-image: linear-gradient(top, #0088cc, #0044cc); background-repeat: repeat-x; filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); border-color: #0044cc #0044cc #002a80; border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); color: #fff; text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); } .datepicker td span.active:hover, .datepicker td span.active:active, .datepicker td span.active.active, .datepicker td span.active.disabled, .datepicker td span.active[disabled] { background-color: #0044cc; } .datepicker td span.active:active, .datepicker td span.active.active { background-color: #003399 \9; } .datepicker td span.old { color: #999999; } .datepicker th.switch { width: 145px; } .datepicker th.next, .datepicker th.prev { font-size: 19.5px; } .datepicker thead tr:first-child th { cursor: pointer; } .datepicker thead tr:first-child th:hover { background: #eeeeee; } .input-append.date .add-on i, .input-prepend.date .add-on i { display: block; cursor: pointer; width: 16px; height: 16px; } +/*! + * Datepicker for Bootstrap + * + * Copyright 2012 Stefan Petre + * Improvements by Andrew Rowls + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + */ +.datepicker { + padding: 4px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + direction: ltr; + /*.dow { + border-top: 1px solid #ddd !important; + }*/ -.bootstrap-timepicker.dropdown-menu { - border-radius: 4px 4px 4px 4px; - display: none; - left: 0; - margin-top: 1px; - padding: 4px; - top: 0; - min-width: 10px; - z-index: 99999; -} -.bootstrap-timepicker.dropdown-menu.open { - display: inline-block; -} -.bootstrap-timepicker.dropdown-menu:before { - border-bottom: 7px solid rgba(0, 0, 0, 0.2); - border-left: 7px solid transparent; - border-right: 7px solid transparent; - content: ""; - left: 6px; - position: absolute; - top: -7px; -} -.bootstrap-timepicker.dropdown-menu:after { - border-bottom: 6px solid #FFFFFF; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - content: ""; - left: 7px; - position: absolute; - top: -6px; -} -.bootstrap-timepicker.modal { - margin-left: -100px; - margin-top: 0; - top: 30%; - width: 200px; } -.bootstrap-timepicker.modal .modal-content { - padding: 0; +.datepicker-inline { + width: 220px; } -.bootstrap-timepicker table { - margin: 0; - width: 100%; +.datepicker.datepicker-rtl { + direction: rtl; } -.bootstrap-timepicker table td { - height: 30px; - margin: 0; - padding: 2px; - text-align: center; +.datepicker.datepicker-rtl table tr td span { + float: right; } -.bootstrap-timepicker table td span { - width: 100%; +.datepicker-dropdown { + top: 0; + left: 0; +} +.datepicker-dropdown: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, 0.2); + position: absolute; + top: -7px; + left: 6px; +} +.datepicker-dropdown:after { + content: ''; + display: inline-block; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + border-bottom: 6px solid #ffffff; + position: absolute; + top: -6px; + left: 7px; +} +.datepicker > div { + display: none; +} +.datepicker.days div.datepicker-days { + display: block; +} +.datepicker.months div.datepicker-months { + display: block; +} +.datepicker.years div.datepicker-years { + display: block; +} +.datepicker table { + margin: 0; +} +.datepicker td, +.datepicker th { + text-align: center; + width: 20px; + height: 20px; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border: none; +} +.table-striped .datepicker table tr td, +.table-striped .datepicker table tr th { + background-color: transparent; +} +.datepicker table tr td.day:hover { + background: #eeeeee; + cursor: pointer; +} +.datepicker table tr td.old, +.datepicker table tr td.new { + color: #999999; +} +.datepicker table tr td.disabled, +.datepicker table tr td.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td.today, +.datepicker table tr td.today:hover, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today.disabled:hover { + background-color: #fde19a; + background-image: -moz-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -ms-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#fdd49a), to(#fdf59a)); + background-image: -webkit-linear-gradient(top, #fdd49a, #fdf59a); + background-image: -o-linear-gradient(top, #fdd49a, #fdf59a); + background-image: linear-gradient(top, #fdd49a, #fdf59a); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fdd49a', endColorstr='#fdf59a', GradientType=0); + border-color: #fdf59a #fdf59a #fbed50; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #000 !important; +} +.datepicker table tr td.today:hover, +.datepicker table tr td.today:hover:hover, +.datepicker table tr td.today.disabled:hover, +.datepicker table tr td.today.disabled:hover:hover, +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active, +.datepicker table tr td.today.disabled, +.datepicker table tr td.today:hover.disabled, +.datepicker table tr td.today.disabled.disabled, +.datepicker table tr td.today.disabled:hover.disabled, +.datepicker table tr td.today[disabled], +.datepicker table tr td.today:hover[disabled], +.datepicker table tr td.today.disabled[disabled], +.datepicker table tr td.today.disabled:hover[disabled] { + background-color: #fdf59a; +} +.datepicker table tr td.today:active, +.datepicker table tr td.today:hover:active, +.datepicker table tr td.today.disabled:active, +.datepicker table tr td.today.disabled:hover:active, +.datepicker table tr td.today.active, +.datepicker table tr td.today:hover.active, +.datepicker table tr td.today.disabled.active, +.datepicker table tr td.today.disabled:hover.active { + background-color: #fbf069 \9; +} +.datepicker table tr td.active, +.datepicker table tr td.active:hover, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td.active:hover, +.datepicker table tr td.active:hover:hover, +.datepicker table tr td.active.disabled:hover, +.datepicker table tr td.active.disabled:hover:hover, +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active, +.datepicker table tr td.active.disabled, +.datepicker table tr td.active:hover.disabled, +.datepicker table tr td.active.disabled.disabled, +.datepicker table tr td.active.disabled:hover.disabled, +.datepicker table tr td.active[disabled], +.datepicker table tr td.active:hover[disabled], +.datepicker table tr td.active.disabled[disabled], +.datepicker table tr td.active.disabled:hover[disabled] { + background-color: #0044cc; +} +.datepicker table tr td.active:active, +.datepicker table tr td.active:hover:active, +.datepicker table tr td.active.disabled:active, +.datepicker table tr td.active.disabled:hover:active, +.datepicker table tr td.active.active, +.datepicker table tr td.active:hover.active, +.datepicker table tr td.active.disabled.active, +.datepicker table tr td.active.disabled:hover.active { + background-color: #003399 \9; +} +.datepicker table tr td span { + display: block; + width: 23%; + height: 54px; + line-height: 54px; + float: left; + margin: 1%; + cursor: pointer; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; +} +.datepicker table tr td span:hover { + background: #eeeeee; +} +.datepicker table tr td span.disabled, +.datepicker table tr td span.disabled:hover { + background: none; + color: #999999; + cursor: default; +} +.datepicker table tr td span.active, +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active.disabled:hover { + background-color: #006dcc; + background-image: -moz-linear-gradient(top, #0088cc, #0044cc); + background-image: -ms-linear-gradient(top, #0088cc, #0044cc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc)); + background-image: -webkit-linear-gradient(top, #0088cc, #0044cc); + background-image: -o-linear-gradient(top, #0088cc, #0044cc); + background-image: linear-gradient(top, #0088cc, #0044cc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0); + border-color: #0044cc #0044cc #002a80; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled=false); + color: #fff; + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25); +} +.datepicker table tr td span.active:hover, +.datepicker table tr td span.active:hover:hover, +.datepicker table tr td span.active.disabled:hover, +.datepicker table tr td span.active.disabled:hover:hover, +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active, +.datepicker table tr td span.active.disabled, +.datepicker table tr td span.active:hover.disabled, +.datepicker table tr td span.active.disabled.disabled, +.datepicker table tr td span.active.disabled:hover.disabled, +.datepicker table tr td span.active[disabled], +.datepicker table tr td span.active:hover[disabled], +.datepicker table tr td span.active.disabled[disabled], +.datepicker table tr td span.active.disabled:hover[disabled] { + background-color: #0044cc; } -.bootstrap-timepicker table td a { - border: 1px solid transparent; - display: inline-block; - margin: 0; - outline: 0 none; - padding: 8px 0; - width: 3em; +.datepicker table tr td span.active:active, +.datepicker table tr td span.active:hover:active, +.datepicker table tr td span.active.disabled:active, +.datepicker table tr td span.active.disabled:hover:active, +.datepicker table tr td span.active.active, +.datepicker table tr td span.active:hover.active, +.datepicker table tr td span.active.disabled.active, +.datepicker table tr td span.active.disabled:hover.active { + background-color: #003399 \9; } -.bootstrap-timepicker table td a:hover { - background-color: #EEEEEE; - border-color: #DDDDDD; - border-radius: 4px 4px 4px 4px; +.datepicker table tr td span.old { + color: #999999; } -.bootstrap-timepicker table td a i { - margin-top: 2px; +.datepicker th.switch { + width: 145px; } -.bootstrap-timepicker table td input { - margin: 0; - text-align: center; - width: 25px; +.datepicker thead tr:first-child th, +.datepicker tfoot tr:first-child th { + cursor: pointer; } -.bootstrap-timepicker-component .add-on { - cursor: pointer; +.datepicker thead tr:first-child th:hover, +.datepicker tfoot tr:first-child th:hover { + background: #eeeeee; } -.bootstrap-timepicker-component .add-on i { - display: block; - height: 16px; - width: 16px; +.datepicker .cw { + font-size: 10px; + width: 12px; + padding: 0 2px 0 5px; + vertical-align: middle; } +.datepicker thead tr:first-child th.cw { + cursor: default; + background-color: transparent; +} +.input-append.date .add-on i, +.input-prepend.date .add-on i { + display: block; + cursor: pointer; + width: 16px; + height: 16px; +} +/*! + * Timepicker Component for Twitter Bootstrap + * + * Copyright 2013 Joris de Wit + * + * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +.bootstrap-timepicker { + position: relative; +} +.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu { + left: auto; + right: 0; +} +.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before { + left: auto; + right: 12px; +} +.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after { + left: auto; + right: 13px; +} +.bootstrap-timepicker .add-on { + cursor: pointer; +} +.bootstrap-timepicker .add-on i { + display: inline-block; + width: 16px; + height: 16px; +} +.bootstrap-timepicker-widget.dropdown-menu { + padding: 2px 3px 2px 2px; +} +.bootstrap-timepicker-widget.dropdown-menu.open { + display: inline-block; +} +.bootstrap-timepicker-widget.dropdown-menu:before { + border-bottom: 7px solid rgba(0, 0, 0, 0.2); + border-left: 7px solid transparent; + border-right: 7px solid transparent; + content: ""; + display: inline-block; + left: 9px; + position: absolute; + top: -7px; +} +.bootstrap-timepicker-widget.dropdown-menu:after { + border-bottom: 6px solid #FFFFFF; + border-left: 6px solid transparent; + border-right: 6px solid transparent; + content: ""; + display: inline-block; + left: 10px; + position: absolute; + top: -6px; +} +.bootstrap-timepicker-widget a.btn, +.bootstrap-timepicker-widget input { + border-radius: 4px; +} +.bootstrap-timepicker-widget table { + width: 100%; + margin: 0; +} +.bootstrap-timepicker-widget table td { + text-align: center; + height: 30px; + margin: 0; + padding: 2px; +} +.bootstrap-timepicker-widget table td:not(.separator) { + min-width: 30px; +} +.bootstrap-timepicker-widget table td span { + width: 100%; +} +.bootstrap-timepicker-widget table td a { + border: 1px transparent solid; + width: 100%; + display: inline-block; + margin: 0; + padding: 8px 0; + outline: 0; + color: #333; +} +.bootstrap-timepicker-widget table td a:hover { + text-decoration: none; + background-color: #eee; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + border-color: #ddd; +} +.bootstrap-timepicker-widget table td a i { + margin-top: 2px; +} +.bootstrap-timepicker-widget table td input { + width: 25px; + margin: 0; + text-align: center; +} +.bootstrap-timepicker-widget .modal-content { + padding: 4px; +} +@media (min-width: 767px) { + .bootstrap-timepicker-widget.modal { + width: 200px; + margin-left: -100px; + } +} +@media (max-width: 767px) { + .bootstrap-timepicker { + width: 100%; + } + .bootstrap-timepicker .dropdown-menu { + width: 100%; + } +} \ No newline at end of file diff --git a/common/lib/timepicker.js b/common/lib/timepicker.js index 9cce032c003..e0d9f51b33a 100644 --- a/common/lib/timepicker.js +++ b/common/lib/timepicker.js @@ -1,806 +1,888 @@ -/* ========================================================= - * bootstrap-timepicker.js - * http://www.github.com/jdewit/bootstrap-timepicker - * ========================================================= - * Copyright 2012 +/*! + * Timepicker Component for Twitter Bootstrap * - * Created By: - * Joris de Wit @joris_dewit + * Copyright 2013 Joris de Wit * - * Contributions By: - * Gilbert @mindeavor - * Koen Punt info@koenpunt.nl - * Nek - * Chris Martin - * Dominic Barnes contact@dominicbarnes.us - * Olivier Louvignes @olouv + * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ========================================================= */ - -!function($) { - - "use strict"; // jshint ;_; - - var isTouch = 'ontouchstart' in window; - - /* TIMEPICKER PUBLIC CLASS DEFINITION - * ================================== */ - var Timepicker = function(element, options) { - this.$element = $(element); - this.options = $.extend({}, $.fn.timepicker.defaults, options, this.$element.data()); - this.minuteStep = this.options.minuteStep || this.minuteStep; - this.secondStep = this.options.secondStep || this.secondStep; - this.showMeridian = this.options.showMeridian || this.showMeridian; - this.showSeconds = this.options.showSeconds || this.showSeconds; - this.showInputs = this.options.showInputs || this.showInputs; - this.disableFocus = this.options.disableFocus || this.disableFocus; - this.template = this.options.template || this.template; - this.modalBackdrop = this.options.modalBackdrop || this.modalBackdrop; - this.defaultTime = this.options.defaultTime || this.defaultTime; - this.open = false; - this.init(); - }; - - Timepicker.prototype = { - - constructor: Timepicker - - , init: function () { - if (this.$element.parent().hasClass('input-append')) { - this.$element.parent('.input-append').find('.add-on').on('click', $.proxy(this.showWidget, this)); - this.$element.on({ - focus: $.proxy(this.highlightUnit, this), - click: $.proxy(this.highlightUnit, this), - keydown: $.proxy(this.elementKeydown, this), - blur: $.proxy(this.blurElement, this) - }); - - } else { - if (this.template) { - this.$element.on({ - focus: $.proxy(this.showWidget, this), - click: $.proxy(this.showWidget, this), - blur: $.proxy(this.blurElement, this) - }); - } else { - this.$element.on({ - focus: $.proxy(this.highlightUnit, this), - click: $.proxy(this.highlightUnit, this), - keydown: $.proxy(this.elementKeydown, this), - blur: $.proxy(this.blurElement, this) - }); - } - } - - - this.$widget = $(this.getTemplate()).appendTo('body'); - - this.$widget.on('click', $.proxy(this.widgetClick, this)); - - if (this.showInputs) { - this.$widget.find('input').on({ - click: function() { this.select(); }, - keydown: $.proxy(this.widgetKeydown, this), - change: $.proxy(this.updateFromWidgetInputs, this) - }); - } - - this.setDefaultTime(this.defaultTime); - } - - , showWidget: function(e) { - e.stopPropagation(); + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +(function($, window, document, undefined) { + 'use strict'; + + // TIMEPICKER PUBLIC CLASS DEFINITION + var Timepicker = function(element, options) { + this.widget = ''; + this.$element = $(element); + this.defaultTime = options.defaultTime; + this.disableFocus = options.disableFocus; + this.isOpen = options.isOpen; + this.minuteStep = options.minuteStep; + this.modalBackdrop = options.modalBackdrop; + this.secondStep = options.secondStep; + this.showInputs = options.showInputs; + this.showMeridian = options.showMeridian; + this.showSeconds = options.showSeconds; + this.template = options.template; + this.appendWidgetTo = options.appendWidgetTo; + + this._init(); + }; + + Timepicker.prototype = { + + constructor: Timepicker, + + _init: function() { + var self = this; + + if (this.$element.parent().hasClass('input-append') || this.$element.parent().hasClass('input-prepend')) { + this.$element.parent('.input-append, .input-prepend').find('.add-on').on({ + 'click.timepicker': $.proxy(this.showWidget, this) + }); + this.$element.on({ + 'focus.timepicker': $.proxy(this.highlightUnit, this), + 'click.timepicker': $.proxy(this.highlightUnit, this), + 'keydown.timepicker': $.proxy(this.elementKeydown, this), + 'blur.timepicker': $.proxy(this.blurElement, this) + }); + } else { + if (this.template) { + this.$element.on({ + 'focus.timepicker': $.proxy(this.showWidget, this), + 'click.timepicker': $.proxy(this.showWidget, this), + 'blur.timepicker': $.proxy(this.blurElement, this) + }); + } else { + this.$element.on({ + 'focus.timepicker': $.proxy(this.highlightUnit, this), + 'click.timepicker': $.proxy(this.highlightUnit, this), + 'keydown.timepicker': $.proxy(this.elementKeydown, this), + 'blur.timepicker': $.proxy(this.blurElement, this) + }); + } + } + + if (this.template !== false) { + this.$widget = $(this.getTemplate()).prependTo(this.$element.parents(this.appendWidgetTo)).on('click', $.proxy(this.widgetClick, this)); + } else { + this.$widget = false; + } + + if (this.showInputs && this.$widget !== false) { + this.$widget.find('input').each(function() { + $(this).on({ + 'click.timepicker': function() { $(this).select(); }, + 'keydown.timepicker': $.proxy(self.widgetKeydown, self) + }); + }); + } + + this.setDefaultTime(this.defaultTime); + }, + + blurElement: function() { + this.highlightedUnit = undefined; + this.updateFromElementVal(); + }, + + decrementHour: function() { + if (this.showMeridian) { + if (this.hour === 1) { + this.hour = 12; + } else if (this.hour === 12) { + this.hour--; + + return this.toggleMeridian(); + } else if (this.hour === 0) { + this.hour = 11; + + return this.toggleMeridian(); + } else { + this.hour--; + } + } else { + if (this.hour === 0) { + this.hour = 23; + } else { + this.hour--; + } + } + this.update(); + }, + + decrementMinute: function(step) { + var newVal; + + if (step) { + newVal = this.minute - step; + } else { + newVal = this.minute - this.minuteStep; + } + + if (newVal < 0) { + this.decrementHour(); + this.minute = newVal + 60; + } else { + this.minute = newVal; + } + this.update(); + }, + + decrementSecond: function() { + var newVal = this.second - this.secondStep; + + if (newVal < 0) { + this.decrementMinute(true); + this.second = newVal + 60; + } else { + this.second = newVal; + } + this.update(); + }, + + elementKeydown: function(e) { + switch (e.keyCode) { + case 9: //tab + this.updateFromElementVal(); + + switch (this.highlightedUnit) { + case 'hour': + e.preventDefault(); + this.highlightNextUnit(); + break; + case 'minute': + if (this.showMeridian || this.showSeconds) { e.preventDefault(); - - if (this.open) { - return; - } - - this.$element.trigger('show'); - - if (isTouch || this.disableFocus) { - this.$element.blur(); - } - - var pos = $.extend({}, this.$element.offset(), { - height: this.$element[0].offsetHeight - }); - - this.updateFromElementVal(); - - $('html') - .one(isTouch ? 'touchstart.timepicker.data-api' : 'click.timepicker.data-api', $.proxy(this.hideWidget, this)) - .on(isTouch ? 'touchstart.timepicker.data-api' : 'click.timepicker.data-api', '.bootstrap-timepicker', function (e) { e.stopPropagation() }); - - if (this.template === 'modal') { - this.$widget.modal('show').on('hidden', $.proxy(this.hideWidget, this)); - } else { - this.$widget.css({ - top: pos.top + pos.height - , left: pos.left - }) - - if (!this.open) { - this.$widget.addClass('open'); - } - } - - this.open = true; - this.$element.trigger('shown'); - } - - , hideWidget: function(){ - this.$element.trigger('hide'); - - if (this.template === 'modal') { - this.$widget.modal('hide'); - } else { - this.$widget.removeClass('open'); - } - this.open = false; - this.$element.trigger('hidden'); - } - - , widgetClick: function(e) { - e.stopPropagation(); + this.highlightNextUnit(); + } + break; + case 'second': + if (this.showMeridian) { e.preventDefault(); - - var action = $(e.target).closest('a').data('action'); - if (action) { - this[action](); - this.update(); - } - } - - , widgetKeydown: function(e) { - var input = $(e.target).closest('input').attr('name'); - - switch (e.keyCode) { - case 9: //tab - if (this.showMeridian) { - if (input == 'meridian') { - this.hideWidget(); - } - } else { - if (this.showSeconds) { - if (input == 'second') { - this.hideWidget(); - } - } else { - if (input == 'minute') { - this.hideWidget(); - } - } - } - break; - case 27: // escape - this.hideWidget(); - break; - case 38: // up arrow - switch (input) { - case 'hour': - this.incrementHour(); - break; - case 'minute': - this.incrementMinute(); - break; - case 'second': - this.incrementSecond(); - break; - case 'meridian': - this.toggleMeridian(); - break; - } - this.update(); - break; - case 40: // down arrow - switch (input) { - case 'hour': - this.decrementHour(); - break; - case 'minute': - this.decrementMinute(); - break; - case 'second': - this.decrementSecond(); - break; - case 'meridian': - this.toggleMeridian(); - break; - } - this.update(); - break; - } - } - - , elementKeydown: function(e) { - var input = this.$element.get(0); - switch (e.keyCode) { - case 0: //input - break; - case 9: //tab - this.updateFromElementVal(); - if (this.showMeridian) { - if (this.highlightedUnit != 'meridian') { - e.preventDefault(); - this.highlightNextUnit(); - } - } else { - if (this.showSeconds) { - if (this.highlightedUnit != 'second') { - e.preventDefault(); - this.highlightNextUnit(); - } - } else { - if (this.highlightedUnit != 'minute') { - e.preventDefault(); - this.highlightNextUnit(); - } - } - } - break; - case 27: // escape - this.updateFromElementVal(); - break; - case 37: // left arrow - this.updateFromElementVal(); - this.highlightPrevUnit(); - break; - case 38: // up arrow - switch (this.highlightedUnit) { - case 'hour': - this.incrementHour(); - break; - case 'minute': - this.incrementMinute(); - break; - case 'second': - this.incrementSecond(); - break; - case 'meridian': - this.toggleMeridian(); - break; - } - this.updateElement(); - break; - case 39: // right arrow - this.updateFromElementVal(); - this.highlightNextUnit(); - break; - case 40: // down arrow - switch (this.highlightedUnit) { - case 'hour': - this.decrementHour(); - break; - case 'minute': - this.decrementMinute(); - break; - case 'second': - this.decrementSecond(); - break; - case 'meridian': - this.toggleMeridian(); - break; - } - this.updateElement(); - break; - } - - if (e.keyCode !== 0 && e.keyCode !== 8 && e.keyCode !== 9 && e.keyCode !== 46) { - e.preventDefault(); - } - } - - , setValues: function(time) { - if (this.showMeridian) { - var arr = time.split(' '); - var timeArray = arr[0].split(':'); - this.meridian = arr[1]; - } else { - var timeArray = time.split(':'); - } - - this.hour = parseInt(timeArray[0], 10); - this.minute = parseInt(timeArray[1], 10); - this.second = parseInt(timeArray[2], 10); - - if (isNaN(this.hour)) { - this.hour = 0; - } - if (isNaN(this.minute)) { - this.minute = 0; - } - - if (this.showMeridian) { - if (this.hour > 12) { - this.hour = 12; - } else if (this.hour < 1) { - this.hour = 1; - } - - if (this.meridian == 'am' || this.meridian == 'a') { - this.meridian = 'AM'; - } else if (this.meridian == 'pm' || this.meridian == 'p') { - this.meridian = 'PM'; - } - - if (this.meridian != 'AM' && this.meridian != 'PM') { - this.meridian = 'AM'; - } - } else { - if (this.hour >= 24) { - this.hour = 23; - } else if (this.hour < 0) { - this.hour = 0; - } - } - - if (this.minute < 0) { - this.minute = 0; - } else if (this.minute >= 60) { - this.minute = 59; - } - - if (this.showSeconds) { - if (isNaN(this.second)) { - this.second = 0; - } else if (this.second < 0) { - this.second = 0; - } else if (this.second >= 60) { - this.second = 59; - } - } - - if ( this.$element.val() != '' ) - this.updateElement(); - this.updateWidget(); - } - - , setMeridian: function(meridian) { - if (meridian == 'a' || meridian == 'am' || meridian == 'AM' ) { - this.meridian = 'AM'; - } else if (meridian == 'p' || meridian == 'pm' || meridian == 'PM' ) { - this.meridian = 'PM'; - } else { - this.updateWidget(); - } - - this.updateElement(); - } - - , setDefaultTime: function(defaultTime){ - if (defaultTime) { - if (defaultTime === 'current') { - var dTime = new Date(); - var hours = dTime.getHours(); - var minutes = Math.floor(dTime.getMinutes() / this.minuteStep) * this.minuteStep; - var seconds = Math.floor(dTime.getSeconds() / this.secondStep) * this.secondStep; - var meridian = "AM"; - if (this.showMeridian) { - if (hours === 0) { - hours = 12; - } else if (hours >= 12) { - if (hours > 12) { - hours = hours - 12; - } - meridian = "PM"; - } else { - meridian = "AM"; - } - } - this.hour = hours; - this.minute = minutes; - this.second = seconds; - this.meridian = meridian; - } else if (defaultTime === 'value') { - this.setValues(this.$element.val()); - } else { - this.setValues(defaultTime); - } - if ( this.$element.val() != '' ) - this.updateElement(); - this.updateWidget(); - } else { - this.hour = 0; - this.minute = 0; - this.second = 0; - } - } - - , formatTime: function(hour, minute, second, meridian) { - hour = hour < 10 ? '0' + hour : hour; - minute = minute < 10 ? '0' + minute : minute; - second = second < 10 ? '0' + second : second; - - return hour + ':' + minute + (this.showSeconds ? ':' + second : '') + (this.showMeridian ? ' ' + meridian : ''); - } - - , getTime: function() { - return this.formatTime(this.hour, this.minute, this.second, this.meridian); - } - - , setTime: function(time) { - this.setValues(time); - this.update(); - } - - , update: function() { - this.updateElement(); - this.updateWidget(); - } - - , blurElement: function() { - this.highlightedUnit = undefined; - this.updateFromElementVal(); - } - - , updateElement: function() { - var time = this.getTime(); - - this.$element.val(time).change(); - - switch (this.highlightedUnit) { - case 'hour': - this.highlightHour(); - break; - case 'minute': - this.highlightMinute(); - break; - case 'second': - this.highlightSecond(); - break; - case 'meridian': - this.highlightMeridian(); - break; - } - } - - , updateWidget: function() { - if (this.showInputs) { - this.$widget.find('input.bootstrap-timepicker-hour').val(this.hour < 10 ? '0' + this.hour : this.hour); - this.$widget.find('input.bootstrap-timepicker-minute').val(this.minute < 10 ? '0' + this.minute : this.minute); - if (this.showSeconds) { - this.$widget.find('input.bootstrap-timepicker-second').val(this.second < 10 ? '0' + this.second : this.second); - } - if (this.showMeridian) { - this.$widget.find('input.bootstrap-timepicker-meridian').val(this.meridian); - } - } else { - this.$widget.find('span.bootstrap-timepicker-hour').text(this.hour); - this.$widget.find('span.bootstrap-timepicker-minute').text(this.minute < 10 ? '0' + this.minute : this.minute); - if (this.showSeconds) { - this.$widget.find('span.bootstrap-timepicker-second').text(this.second < 10 ? '0' + this.second : this.second); - } - if (this.showMeridian) { - this.$widget.find('span.bootstrap-timepicker-meridian').text(this.meridian); - } - } - } - - , updateFromElementVal: function (e) { - var time = this.$element.val(); - if (time) { - this.setValues(time); - this.updateWidget(); - } - } - - , updateFromWidgetInputs: function () { - var time = $('input.bootstrap-timepicker-hour', this.$widget).val() + ':' + - $('input.bootstrap-timepicker-minute', this.$widget).val() + - (this.showSeconds ? - ':' + $('input.bootstrap-timepicker-second', this.$widget).val() - : '') + - (this.showMeridian ? - ' ' + $('input.bootstrap-timepicker-meridian', this.$widget).val() - : ''); - - this.setValues(time); - } - - , getCursorPosition: function() { - var input = this.$element.get(0); - - if ('selectionStart' in input) { - // Standard-compliant browsers - return input.selectionStart; - } else if (document.selection) { - // IE fix - input.focus(); - var sel = document.selection.createRange(); - var selLen = document.selection.createRange().text.length; - sel.moveStart('character', - input.value.length); - - return sel.text.length - selLen; - } - } - - , highlightUnit: function () { - var input = this.$element.get(0); - - this.position = this.getCursorPosition(); - if (this.position >= 0 && this.position <= 2) { - this.highlightHour(); - } else if (this.position >= 3 && this.position <= 5) { - this.highlightMinute(); - } else if (this.position >= 6 && this.position <= 8) { - if (this.showSeconds) { - this.highlightSecond(); - } else { - this.highlightMeridian(); - } - } else if (this.position >= 9 && this.position <= 11) { - this.highlightMeridian(); - } - } - - , highlightNextUnit: function() { - switch (this.highlightedUnit) { - case 'hour': - this.highlightMinute(); - break; - case 'minute': - if (this.showSeconds) { - this.highlightSecond(); - } else { - this.highlightMeridian(); - } - break; - case 'second': - this.highlightMeridian(); - break; - case 'meridian': - this.highlightHour(); - break; - } - } - - , highlightPrevUnit: function() { - switch (this.highlightedUnit) { - case 'hour': - this.highlightMeridian(); - break; - case 'minute': - this.highlightHour(); - break; - case 'second': - this.highlightMinute(); - break; - case 'meridian': - if (this.showSeconds) { - this.highlightSecond(); - } else { - this.highlightMinute(); - } - break; - } - } - - , highlightHour: function() { - this.highlightedUnit = 'hour'; - this.$element.get(0).setSelectionRange(0,2); - } - - , highlightMinute: function() { - this.highlightedUnit = 'minute'; - this.$element.get(0).setSelectionRange(3,5); - } - - , highlightSecond: function() { - this.highlightedUnit = 'second'; - this.$element.get(0).setSelectionRange(6,8); - } - - , highlightMeridian: function() { - this.highlightedUnit = 'meridian'; - if (this.showSeconds) { - this.$element.get(0).setSelectionRange(9,11); - } else { - this.$element.get(0).setSelectionRange(6,8); - } - } - - , incrementHour: function() { - if (this.showMeridian) { - if (this.hour === 11) { - this.toggleMeridian(); - } else if (this.hour === 12) { - return this.hour = 1; - } - } - if (this.hour === 23) { - return this.hour = 0; - } - this.hour = this.hour + 1; - } - - , decrementHour: function() { - if (this.showMeridian) { - if (this.hour === 1) { - return this.hour = 12; - } - else if (this.hour === 12) { - this.toggleMeridian(); - } - } - if (this.hour === 0) { - return this.hour = 23; - } - this.hour = this.hour - 1; - } - - , incrementMinute: function() { - var newVal = this.minute + this.minuteStep - (this.minute % this.minuteStep); - if (newVal > 59) { - this.incrementHour(); - this.minute = newVal - 60; - } else { - this.minute = newVal; - } - } - - , decrementMinute: function() { - var newVal = this.minute - this.minuteStep; - if (newVal < 0) { - this.decrementHour(); - this.minute = newVal + 60; - } else { - this.minute = newVal; - } - } - - , incrementSecond: function() { - var newVal = this.second + this.secondStep - (this.second % this.secondStep); - if (newVal > 59) { - this.incrementMinute(); - this.second = newVal - 60; + this.highlightNextUnit(); + } + break; + } + break; + case 27: // escape + this.updateFromElementVal(); + break; + case 37: // left arrow + e.preventDefault(); + this.highlightPrevUnit(); + this.updateFromElementVal(); + break; + case 38: // up arrow + e.preventDefault(); + switch (this.highlightedUnit) { + case 'hour': + this.incrementHour(); + this.highlightHour(); + break; + case 'minute': + this.incrementMinute(); + this.highlightMinute(); + break; + case 'second': + this.incrementSecond(); + this.highlightSecond(); + break; + case 'meridian': + this.toggleMeridian(); + this.highlightMeridian(); + break; + } + break; + case 39: // right arrow + e.preventDefault(); + this.updateFromElementVal(); + this.highlightNextUnit(); + break; + case 40: // down arrow + e.preventDefault(); + switch (this.highlightedUnit) { + case 'hour': + this.decrementHour(); + this.highlightHour(); + break; + case 'minute': + this.decrementMinute(); + this.highlightMinute(); + break; + case 'second': + this.decrementSecond(); + this.highlightSecond(); + break; + case 'meridian': + this.toggleMeridian(); + this.highlightMeridian(); + break; + } + break; + } + }, + + formatTime: function(hour, minute, second, meridian) { + hour = hour < 10 ? '0' + hour : hour; + minute = minute < 10 ? '0' + minute : minute; + second = second < 10 ? '0' + second : second; + + return hour + ':' + minute + (this.showSeconds ? ':' + second : '') + (this.showMeridian ? ' ' + meridian : ''); + }, + + getCursorPosition: function() { + var input = this.$element.get(0); + + if ('selectionStart' in input) {// Standard-compliant browsers + + return input.selectionStart; + } else if (document.selection) {// IE fix + input.focus(); + var sel = document.selection.createRange(), + selLen = document.selection.createRange().text.length; + + sel.moveStart('character', - input.value.length); + + return sel.text.length - selLen; + } + }, + + getTemplate: function() { + var template, + hourTemplate, + minuteTemplate, + secondTemplate, + meridianTemplate, + templateContent; + + if (this.showInputs) { + hourTemplate = ''; + minuteTemplate = ''; + secondTemplate = ''; + meridianTemplate = ''; + } else { + hourTemplate = ''; + minuteTemplate = ''; + secondTemplate = ''; + meridianTemplate = ''; + } + + templateContent = '