1 /** https://github.com/perifer/timePicker - b5195df3 */
3 * A time picker for jQuery
5 * Dual licensed under the MIT and GPL licenses.
6 * Copyright (c) 2009 Anders Fajerson
8 * @author Anders Fajerson (http://perifer.se)
9 * @example $("#mytime").timePicker();
10 * @example $("#mytime").timePicker({step:30, startTime:"15:00", endTime:"18:00"});
12 * Based on timePicker by Sam Collet (http://www.texotela.co.uk/code/jquery/timepicker/)
15 * step: # of minutes to step the time by
16 * startTime: beginning of the range of acceptable times
17 * endTime: end of the range of acceptable times
18 * separator: separator string to use between hours and minutes (e.g. ':')
19 * show24Hours: use a 24-hour scheme
23 $.fn
.timePicker = function(options
) {
24 // Build main options before element iteration
25 var settings
= $.extend({}, $.fn
.timePicker
.defaults
, options
);
27 return this.each(function() {
28 $.timePicker(this, settings
);
32 $.timePicker = function (elm
, settings
) {
34 return e
.timePicker
|| (e
.timePicker
= new jQuery
._timePicker(e
, settings
));
37 $.timePicker
.version
= '0.3';
39 $._timePicker = function(elm
, settings
) {
43 var startTime
= timeToDate(settings
.startTime
, settings
);
44 var endTime
= timeToDate(settings
.endTime
, settings
);
45 var selectedClass
= "selected";
46 var selectedSelector
= "li." + selectedClass
;
48 $(elm
).attr('autocomplete', 'OFF'); // Disable browser autocomplete
51 var time
= new Date(startTime
); // Create a new date object.
52 while(time
<= endTime
) {
53 times
[times
.length
] = formatTime(time
, settings
);
54 time
= new Date(time
.setMinutes(time
.getMinutes() + settings
.step
));
57 var $tpDiv
= $('<div class="time-picker'+ (settings
.show24Hours
? '' : ' time-picker-12hours') +'"></div>');
58 var $tpList
= $('<ul></ul>');
61 for(var i
= 0; i
< times
.length
; i
++) {
62 $tpList
.append("<li>" + times
[i
] + "</li>");
64 $tpDiv
.append($tpList
);
65 // Append the timPicker to the body and position it.
66 $tpDiv
.appendTo('body').hide();
68 // Store the mouse state, used by the blur event. Use mouseover instead of
69 // mousedown since Opera fires blur before mousedown.
70 $tpDiv
.mouseover(function() {
72 }).mouseout(function() {
76 $("li", $tpList
).mouseover(function() {
78 $(selectedSelector
, $tpDiv
).removeClass(selectedClass
);
79 $(this).addClass(selectedClass
);
81 }).mousedown(function() {
84 setTimeVal(elm
, this, $tpDiv
, settings
);
88 var showPicker = function() {
89 if ($tpDiv
.is(":visible")) {
92 $("li", $tpDiv
).removeClass(selectedClass
);
95 var elmOffset
= $(elm
).offset();
96 $tpDiv
.css({'top':elmOffset
.top
+ elm
.offsetHeight
, 'left':elmOffset
.left
});
98 // Show picker. This has to be done before scrollTop is set since that
99 // can't be done on hidden elements.
102 // Try to find a time in the list that matches the entered time.
103 var time
= elm
.value
? timeStringToDate(elm
.value
, settings
) : startTime
;
104 var startMin
= startTime
.getHours() * 60 + startTime
.getMinutes();
105 var min
= (time
.getHours() * 60 + time
.getMinutes()) - startMin
;
106 var steps
= Math
.round(min
/ settings
.step
);
107 var roundTime
= normaliseTime(new Date(0, 0, 0, 0, (steps
* settings
.step
+ startMin
), 0));
108 roundTime
= (startTime
< roundTime
&& roundTime
<= endTime
) ? roundTime
: startTime
;
109 var $matchedTime
= $("li:contains(" + formatTime(roundTime
, settings
) + ")", $tpDiv
);
111 if ($matchedTime
.length
) {
112 $matchedTime
.addClass(selectedClass
);
113 // Scroll to matched time.
114 $tpDiv
[0].scrollTop
= $matchedTime
[0].offsetTop
;
118 // Attach to click as well as focus so timePicker can be shown again when
119 // clicking on the input when it already has focus.
120 $(elm
).focus(showPicker
).click(showPicker
);
121 // Hide timepicker on blur
122 $(elm
).blur(function() {
127 // Keypress doesn't repeat on Safari for non-text keys.
128 // Keydown doesn't repeat on Firefox and Opera on Mac.
129 // Using kepress for Opera and Firefox and keydown for the rest seems to
130 // work with up/down/enter/esc.
131 var event
= ($.browser
.opera
|| $.browser
.mozilla
) ? 'keypress' : 'keydown';
132 $(elm
)[event
](function(e
) {
135 var top
= $tpDiv
[0].scrollTop
;
137 case 38: // Up arrow.
138 // Just show picker if it's hidden.
142 $selected
= $(selectedSelector
, $tpList
);
143 var prev
= $selected
.prev().addClass(selectedClass
)[0];
145 $selected
.removeClass(selectedClass
);
146 // Scroll item into view.
147 if (prev
.offsetTop
< top
) {
148 $tpDiv
[0].scrollTop
= top
- prev
.offsetHeight
;
152 // Loop to next item.
153 $selected
.removeClass(selectedClass
);
154 prev
= $("li:last", $tpList
).addClass(selectedClass
)[0];
155 $tpDiv
[0].scrollTop
= prev
.offsetTop
- prev
.offsetHeight
;
159 case 40: // Down arrow, similar in behaviour to up arrow.
163 $selected
= $(selectedSelector
, $tpList
);
164 var next
= $selected
.next().addClass(selectedClass
)[0];
166 $selected
.removeClass(selectedClass
);
167 if (next
.offsetTop
+ next
.offsetHeight
> top
+ $tpDiv
[0].offsetHeight
) {
168 $tpDiv
[0].scrollTop
= top
+ next
.offsetHeight
;
172 $selected
.removeClass(selectedClass
);
173 next
= $("li:first", $tpList
).addClass(selectedClass
)[0];
174 $tpDiv
[0].scrollTop
= 0;
179 if ($tpDiv
.is(":visible")) {
180 var sel
= $(selectedSelector
, $tpList
)[0];
181 setTimeVal(elm
, sel
, $tpDiv
, settings
);
192 $(elm
).keyup(function(e
) {
195 // Helper function to get an inputs current time as Date object.
196 // Returns a Date object.
197 this.getTime = function() {
198 return timeStringToDate(elm
.value
, settings
);
200 // Helper function to set a time input.
201 // Takes a Date object or string.
202 this.setTime = function(time
) {
203 elm
.value
= formatTime(timeToDate(time
, settings
), settings
);
204 // Trigger element's change events.
211 $.fn
.timePicker
.defaults
= {
213 startTime
: new Date(0, 0, 0, 0, 0, 0),
214 endTime
: new Date(0, 0, 0, 23, 30, 0),
219 // Private functions.
221 function setTimeVal(elm
, sel
, $tpDiv
, settings
) {
222 // Update input field
223 elm
.value
= $(sel
).text();
224 // Trigger element's change events.
226 // Keep focus for all but IE (which doesn't like it)
227 if (!$.browser
.msie
) {
234 function formatTime(time
, settings
) {
235 var h
= time
.getHours();
236 var hours
= settings
.show24Hours
? h
: (((h
+ 11) % 12) + 1);
237 var minutes
= time
.getMinutes();
238 return formatNumber(hours
) + settings
.separator
+ formatNumber(minutes
) + (settings
.show24Hours
? '' : ((h
< 12) ? ' AM' : ' PM'));
241 function formatNumber(value
) {
242 return (value
< 10 ? '0' : '') + value
;
245 function timeToDate(input
, settings
) {
246 return (typeof input
== 'object') ? normaliseTime(input
) : timeStringToDate(input
, settings
);
249 function timeStringToDate(input
, settings
) {
251 var array
= input
.split(settings
.separator
);
252 var hours
= parseFloat(array
[0]);
253 var minutes
= parseFloat(array
[1]);
255 // Convert AM/PM hour to 24-hour format.
256 if (!settings
.show24Hours
) {
257 if (hours
=== 12 && input
.indexOf('AM') !== -1) {
260 else if (hours
!== 12 && input
.indexOf('PM') !== -1) {
264 var time
= new Date(0, 0, 0, hours
, minutes
, 0);
265 return normaliseTime(time
);
270 /* Normalise time object to a common date. */
271 function normaliseTime(time
) {
272 time
.setFullYear(2001);