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