]> git.mxchange.org Git - friendica-addons.git/blob - dav/timepicker/jquery.timePicker.js
Add Temporal::local() shorthand for Temporal::convert()
[friendica-addons.git] / dav / timepicker / jquery.timePicker.js
1 /*
2  * A time picker for jQuery
3  *
4  * Dual licensed under the MIT and GPL licenses.
5  * Copyright (c) 2009 Anders Fajerson
6  * @name     timePicker
7  * @author   Anders Fajerson (http://perifer.se)
8  * @example  $("#mytime").timePicker();
9  * @example  $("#mytime").timePicker({step:30, startTime:"15:00", endTime:"18:00"});
10  *
11  * Based on timePicker by Sam Collet (http://www.texotela.co.uk/code/jquery/timepicker/)
12  *
13  * Options:
14  *   step: # of minutes to step the time by
15  *   startTime: beginning of the range of acceptable times
16  *   endTime: end of the range of acceptable times
17  *   separator: separator string to use between hours and minutes (e.g. ':')
18  *   show24Hours: use a 24-hour scheme
19  */
20
21 (function($){
22   $.fn.timePicker = function(options) {
23     // Build main options before element iteration
24     var settings = $.extend({}, $.fn.timePicker.defaults, options);
25
26     return this.each(function() {
27       $.timePicker(this, settings);
28     });
29   };
30
31   $.timePicker = function (elm, settings) {
32     var e = $(elm)[0];
33     return e.timePicker || (e.timePicker = new jQuery._timePicker(e, settings));
34   };
35
36   $.timePicker.version = '0.3';
37
38   $._timePicker = function(elm, settings) {
39
40     var tpOver = false;
41     var keyDown = false;
42     var startTime = timeToDate(settings.startTime, settings);
43     var endTime = timeToDate(settings.endTime, settings);
44     var selectedClass = "selected";
45     var selectedSelector = "li." + selectedClass;
46
47     $(elm).attr('autocomplete', 'OFF'); // Disable browser autocomplete
48
49     var times = [];
50     var time = new Date(startTime); // Create a new date object.
51     while(time <= endTime) {
52       times[times.length] = formatTime(time, settings);
53       time = new Date(time.setMinutes(time.getMinutes() + settings.step));
54     }
55
56     var $tpDiv = $('<div class="time-picker'+ (settings.show24Hours ? '' : ' time-picker-12hours') +'"></div>');
57     var $tpList = $('<ul></ul>');
58
59     // Build the list.
60     for(var i = 0; i < times.length; i++) {
61       $tpList.append("<li>" + times[i] + "</li>");
62     }
63     $tpDiv.append($tpList);
64     // Append the timPicker to the body and position it.
65     $tpDiv.appendTo('body').hide();
66
67     // Store the mouse state, used by the blur event. Use mouseover instead of
68     // mousedown since Opera fires blur before mousedown.
69     $tpDiv.mouseover(function() {
70       tpOver = true;
71     }).mouseout(function() {
72       tpOver = false;
73     });
74
75     $("li", $tpList).mouseover(function() {
76       if (!keyDown) {
77         $(selectedSelector, $tpDiv).removeClass(selectedClass);
78         $(this).addClass(selectedClass);
79       }
80     }).mousedown(function() {
81        tpOver = true;
82     }).click(function() {
83       setTimeVal(elm, this, $tpDiv, settings);
84       tpOver = false;
85     });
86
87     var showPicker = function() {
88       if ($tpDiv.is(":visible")) {
89         return false;
90       }
91       $("li", $tpDiv).removeClass(selectedClass);
92
93       // Position
94       var elmOffset = $(elm).offset();
95       $tpDiv.css({'top':elmOffset.top + elm.offsetHeight, 'left':elmOffset.left});
96
97       // Show picker. This has to be done before scrollTop is set since that
98       // can't be done on hidden elements.
99       $tpDiv.show();
100
101       // Try to find a time in the list that matches the entered time.
102       var time = elm.value ? timeStringToDate(elm.value, settings) : startTime;
103       var startMin = startTime.getHours() * 60 + startTime.getMinutes();
104       var min = (time.getHours() * 60 + time.getMinutes()) - startMin;
105       var steps = Math.round(min / settings.step);
106       var roundTime = normaliseTime(new Date(0, 0, 0, 0, (steps * settings.step + startMin), 0));
107       roundTime = (startTime < roundTime && roundTime <= endTime) ? roundTime : startTime;
108       var $matchedTime = $("li:contains(" + formatTime(roundTime, settings) + ")", $tpDiv);
109
110       if ($matchedTime.length) {
111         $matchedTime.addClass(selectedClass);
112         // Scroll to matched time.
113         $tpDiv[0].scrollTop = $matchedTime[0].offsetTop;
114       }
115       return true;
116     };
117     // Attach to click as well as focus so timePicker can be shown again when
118     // clicking on the input when it already has focus.
119     $(elm).focus(showPicker).click(showPicker);
120     // Hide timepicker on blur
121     $(elm).blur(function() {
122       if (!tpOver) {
123         $tpDiv.hide();
124       }
125     });
126     // Keypress doesn't repeat on Safari for non-text keys.
127     // Keydown doesn't repeat on Firefox and Opera on Mac.
128     // Using kepress for Opera and Firefox and keydown for the rest seems to
129     // work with up/down/enter/esc.
130     var event = ($.browser.opera || $.browser.mozilla) ? 'keypress' : 'keydown';
131     $(elm)[event](function(e) {
132       var $selected;
133       keyDown = true;
134       var top = $tpDiv[0].scrollTop;
135       switch (e.keyCode) {
136         case 38: // Up arrow.
137           // Just show picker if it's hidden.
138           if (showPicker()) {
139             return false;
140           };
141           $selected = $(selectedSelector, $tpList);
142           var prev = $selected.prev().addClass(selectedClass)[0];
143           if (prev) {
144             $selected.removeClass(selectedClass);
145             // Scroll item into view.
146             if (prev.offsetTop < top) {
147               $tpDiv[0].scrollTop = top - prev.offsetHeight;
148             }
149           }
150           else {
151             // Loop to next item.
152             $selected.removeClass(selectedClass);
153             prev = $("li:last", $tpList).addClass(selectedClass)[0];
154             $tpDiv[0].scrollTop = prev.offsetTop - prev.offsetHeight;
155           }
156           return false;
157           break;
158         case 40: // Down arrow, similar in behaviour to up arrow.
159           if (showPicker()) {
160             return false;
161           };
162           $selected = $(selectedSelector, $tpList);
163           var next = $selected.next().addClass(selectedClass)[0];
164           if (next) {
165             $selected.removeClass(selectedClass);
166             if (next.offsetTop + next.offsetHeight > top + $tpDiv[0].offsetHeight) {
167               $tpDiv[0].scrollTop = top + next.offsetHeight;
168             }
169           }
170           else {
171             $selected.removeClass(selectedClass);
172             next = $("li:first", $tpList).addClass(selectedClass)[0];
173             $tpDiv[0].scrollTop = 0;
174           }
175           return false;
176           break;
177         case 13: // Enter
178           if ($tpDiv.is(":visible")) {
179             var sel = $(selectedSelector, $tpList)[0];
180             setTimeVal(elm, sel, $tpDiv, settings);
181           }
182           return false;
183           break;
184         case 27: // Esc
185           $tpDiv.hide();
186           return false;
187           break;
188       }
189       return true;
190     });
191     $(elm).keyup(function(e) {
192       keyDown = false;
193     });
194     // Helper function to get an inputs current time as Date object.
195     // Returns a Date object.
196     this.getTime = function() {
197       return timeStringToDate(elm.value, settings);
198     };
199     // Helper function to set a time input.
200     // Takes a Date object or string.
201     this.setTime = function(time) {
202       elm.value = formatTime(timeToDate(time, settings), settings);
203       // Trigger element's change events.
204       $(elm).change();
205     };
206
207   }; // End fn;
208
209   // Plugin defaults.
210   $.fn.timePicker.defaults = {
211     step:30,
212     startTime: new Date(0, 0, 0, 0, 0, 0),
213     endTime: new Date(0, 0, 0, 23, 30, 0),
214     separator: ':',
215     show24Hours: true
216   };
217
218   // Private functions.
219
220   function setTimeVal(elm, sel, $tpDiv, settings) {
221     // Update input field
222     elm.value = $(sel).text();
223     // Trigger element's change events.
224     $(elm).change();
225     // Keep focus for all but IE (which doesn't like it)
226     if (!$.browser.msie) {
227       elm.focus();
228     }
229     // Hide picker
230     $tpDiv.hide();
231   }
232
233   function formatTime(time, settings) {
234     var h = time.getHours();
235     var hours = settings.show24Hours ? h : (((h + 11) % 12) + 1);
236     var minutes = time.getMinutes();
237     return formatNumber(hours) + settings.separator + formatNumber(minutes) + (settings.show24Hours ? '' : ((h < 12) ? ' AM' : ' PM'));
238   }
239
240   function formatNumber(value) {
241     return (value < 10 ? '0' : '') + value;
242   }
243
244   function timeToDate(input, settings) {
245     return (typeof input == 'object') ? normaliseTime(input) : timeStringToDate(input, settings);
246   }
247
248   function timeStringToDate(input, settings) {
249     if (input) {
250       var array = input.split(settings.separator);
251       var hours = parseFloat(array[0]);
252       var minutes = parseFloat(array[1]);
253
254       // Convert AM/PM hour to 24-hour format.
255       if (!settings.show24Hours) {
256         if (hours === 12 && input.indexOf('AM') !== -1) {
257           hours = 0;
258         }
259         else if (hours !== 12 && input.indexOf('PM') !== -1) {
260           hours += 12;
261         }
262       }
263       var time = new Date(0, 0, 0, hours, minutes, 0);
264       return normaliseTime(time);
265     }
266     return null;
267   }
268
269   /* Normalise time object to a common date. */
270   function normaliseTime(time) {
271     time.setFullYear(2001);
272     time.setMonth(0);
273     time.setDate(0);
274     return time;
275   }
276
277 })(jQuery);