[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / prive / formulaires / dateur / jquery.time_picker.js
1 /** https://github.com/perifer/timePicker - b5195df3 */
2 /*
3 * A time picker for jQuery
4 *
5 * Dual licensed under the MIT and GPL licenses.
6 * Copyright (c) 2009 Anders Fajerson
7 * @name timePicker
8 * @author Anders Fajerson (http://perifer.se)
9 * @example $("#mytime").timePicker();
10 * @example $("#mytime").timePicker({step:30, startTime:"15:00", endTime:"18:00"});
11 *
12 * Based on timePicker by Sam Collet (http://www.texotela.co.uk/code/jquery/timepicker/)
13 *
14 * Options:
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
20 */
21
22 (function($){
23 $.fn.timePicker = function(options) {
24 // Build main options before element iteration
25 var settings = $.extend({}, $.fn.timePicker.defaults, options);
26
27 return this.each(function() {
28 $.timePicker(this, settings);
29 });
30 };
31
32 $.timePicker = function (elm, settings) {
33 var e = $(elm)[0];
34 return e.timePicker || (e.timePicker = new jQuery._timePicker(e, settings));
35 };
36
37 $.timePicker.version = '0.3';
38
39 $._timePicker = function(elm, settings) {
40
41 var tpOver = false;
42 var keyDown = false;
43 var startTime = timeToDate(settings.startTime, settings);
44 var endTime = timeToDate(settings.endTime, settings);
45 var selectedClass = "selected";
46 var selectedSelector = "li." + selectedClass;
47
48 $(elm).attr('autocomplete', 'OFF'); // Disable browser autocomplete
49
50 var times = [];
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));
55 }
56
57 var $tpDiv = $('<div class="time-picker'+ (settings.show24Hours ? '' : ' time-picker-12hours') +'"></div>');
58 var $tpList = $('<ul></ul>');
59
60 // Build the list.
61 for(var i = 0; i < times.length; i++) {
62 $tpList.append("<li>" + times[i] + "</li>");
63 }
64 $tpDiv.append($tpList);
65 // Append the timPicker to the body and position it.
66 $tpDiv.appendTo('body').hide();
67
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() {
71 tpOver = true;
72 }).mouseout(function() {
73 tpOver = false;
74 });
75
76 $("li", $tpList).mouseover(function() {
77 if (!keyDown) {
78 $(selectedSelector, $tpDiv).removeClass(selectedClass);
79 $(this).addClass(selectedClass);
80 }
81 }).mousedown(function() {
82 tpOver = true;
83 }).click(function() {
84 setTimeVal(elm, this, $tpDiv, settings);
85 tpOver = false;
86 });
87
88 var showPicker = function() {
89 if ($tpDiv.is(":visible")) {
90 return false;
91 }
92 $("li", $tpDiv).removeClass(selectedClass);
93
94 // Position
95 var elmOffset = $(elm).offset();
96 $tpDiv.css({'top':elmOffset.top + elm.offsetHeight, 'left':elmOffset.left});
97
98 // Show picker. This has to be done before scrollTop is set since that
99 // can't be done on hidden elements.
100 $tpDiv.show();
101
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);
110
111 if ($matchedTime.length) {
112 $matchedTime.addClass(selectedClass);
113 // Scroll to matched time.
114 $tpDiv[0].scrollTop = $matchedTime[0].offsetTop;
115 }
116 return true;
117 };
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() {
123 if (!tpOver) {
124 $tpDiv.hide();
125 }
126 });
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) {
133 var $selected;
134 keyDown = true;
135 var top = $tpDiv[0].scrollTop;
136 switch (e.keyCode) {
137 case 38: // Up arrow.
138 // Just show picker if it's hidden.
139 if (showPicker()) {
140 return false;
141 };
142 $selected = $(selectedSelector, $tpList);
143 var prev = $selected.prev().addClass(selectedClass)[0];
144 if (prev) {
145 $selected.removeClass(selectedClass);
146 // Scroll item into view.
147 if (prev.offsetTop < top) {
148 $tpDiv[0].scrollTop = top - prev.offsetHeight;
149 }
150 }
151 else {
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;
156 }
157 return false;
158 break;
159 case 40: // Down arrow, similar in behaviour to up arrow.
160 if (showPicker()) {
161 return false;
162 };
163 $selected = $(selectedSelector, $tpList);
164 var next = $selected.next().addClass(selectedClass)[0];
165 if (next) {
166 $selected.removeClass(selectedClass);
167 if (next.offsetTop + next.offsetHeight > top + $tpDiv[0].offsetHeight) {
168 $tpDiv[0].scrollTop = top + next.offsetHeight;
169 }
170 }
171 else {
172 $selected.removeClass(selectedClass);
173 next = $("li:first", $tpList).addClass(selectedClass)[0];
174 $tpDiv[0].scrollTop = 0;
175 }
176 return false;
177 break;
178 case 13: // Enter
179 if ($tpDiv.is(":visible")) {
180 var sel = $(selectedSelector, $tpList)[0];
181 setTimeVal(elm, sel, $tpDiv, settings);
182 }
183 return false;
184 break;
185 case 27: // Esc
186 $tpDiv.hide();
187 return false;
188 break;
189 }
190 return true;
191 });
192 $(elm).keyup(function(e) {
193 keyDown = false;
194 });
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);
199 };
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.
205 $(elm).change();
206 };
207
208 }; // End fn;
209
210 // Plugin defaults.
211 $.fn.timePicker.defaults = {
212 step:30,
213 startTime: new Date(0, 0, 0, 0, 0, 0),
214 endTime: new Date(0, 0, 0, 23, 30, 0),
215 separator: ':',
216 show24Hours: true
217 };
218
219 // Private functions.
220
221 function setTimeVal(elm, sel, $tpDiv, settings) {
222 // Update input field
223 elm.value = $(sel).text();
224 // Trigger element's change events.
225 $(elm).change();
226 // Keep focus for all but IE (which doesn't like it)
227 if (!$.browser.msie) {
228 elm.focus();
229 }
230 // Hide picker
231 $tpDiv.hide();
232 }
233
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'));
239 }
240
241 function formatNumber(value) {
242 return (value < 10 ? '0' : '') + value;
243 }
244
245 function timeToDate(input, settings) {
246 return (typeof input == 'object') ? normaliseTime(input) : timeStringToDate(input, settings);
247 }
248
249 function timeStringToDate(input, settings) {
250 if (input) {
251 var array = input.split(settings.separator);
252 var hours = parseFloat(array[0]);
253 var minutes = parseFloat(array[1]);
254
255 // Convert AM/PM hour to 24-hour format.
256 if (!settings.show24Hours) {
257 if (hours === 12 && input.indexOf('AM') !== -1) {
258 hours = 0;
259 }
260 else if (hours !== 12 && input.indexOf('PM') !== -1) {
261 hours += 12;
262 }
263 }
264 var time = new Date(0, 0, 0, hours, minutes, 0);
265 return normaliseTime(time);
266 }
267 return null;
268 }
269
270 /* Normalise time object to a common date. */
271 function normaliseTime(time) {
272 time.setFullYear(2001);
273 time.setMonth(0);
274 time.setDate(0);
275 return time;
276 }
277
278 })(jQuery);