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