[SPIP][PLUGINS] v3.0-->v3.2
[lhc/web/www.git] / www / prive / formulaires / dateur / jquery.time_picker.js
index 8e21cce..71b4c5a 100644 (file)
@@ -1,43 +1,52 @@
-/*
- * Copyright (c) 2006 Sam Collett (http://www.texotela.co.uk)
- * Licensed under the MIT License:
- * http://www.opensource.org/licenses/mit-license.php
- */
+/** https://github.com/perifer/timePicker - b5195df3 */
 /*
  * A time picker for jQuery
- * Based on original timePicker by Sam Collet (http://www.texotela.co.uk)
+ *
+ * Dual licensed under the MIT and GPL licenses.
+ * Copyright (c) 2009 Anders Fajerson
  * @name     timePicker
- * @version  0.1 
  * @author   Anders Fajerson (http://perifer.se)
  * @example  $("#mytime").timePicker();
- * @example  $("#mytime").timePicker({step:30, startTime:"15:00", endTime:"18:00"}); 
+ * @example  $("#mytime").timePicker({step:30, startTime:"15:00", endTime:"18:00"});
+ *
+ * Based on timePicker by Sam Collet (http://www.texotela.co.uk/code/jquery/timepicker/)
+ *
+ * Options:
+ *   step: # of minutes to step the time by
+ *   startTime: beginning of the range of acceptable times
+ *   endTime: end of the range of acceptable times
+ *   separator: separator string to use between hours and minutes (e.g. ':')
+ *   show24Hours: use a 24-hour scheme
  */
-;if (window.jQuery)
+
 (function($){
-  
   $.fn.timePicker = function(options) {
     // Build main options before element iteration
-         var settings = $.extend({}, $.fn.timePicker.defaults, options);  
-    
+    var settings = $.extend({}, $.fn.timePicker.defaults, options);
+
     return this.each(function() {
       $.timePicker(this, settings);
     });
   };
-  
+
   $.timePicker = function (elm, settings) {
-    var elm = $(elm)[0];  
-    return elm.timePicker || (elm.timePicker = new jQuery._timePicker(elm, settings));
+    var e = $(elm)[0];
+    return e.timePicker || (e.timePicker = new jQuery._timePicker(e, settings));
   };
-  
+
+  $.timePicker.version = '0.3';
+
   $._timePicker = function(elm, settings) {
-    
+
     var tpOver = false;
-    var startTime = normaliseTime(settings.startTime);
-    var endTime = normaliseTime(settings.endTime);
-    
+    var keyDown = false;
+    var startTime = timeToDate(settings.startTime, settings);
+    var endTime = timeToDate(settings.endTime, settings);
+    var selectedClass = "selected";
+    var selectedSelector = "li." + selectedClass;
+
     $(elm).attr('autocomplete', 'OFF'); // Disable browser autocomplete
-    
+
     var times = [];
     var time = new Date(startTime); // Create a new date object.
     while(time <= endTime) {
 
     var $tpDiv = $('<div class="time-picker'+ (settings.show24Hours ? '' : ' time-picker-12hours') +'"></div>');
     var $tpList = $('<ul></ul>');
-    
+
     // Build the list.
     for(var i = 0; i < times.length; i++) {
       $tpList.append("<li>" + times[i] + "</li>");
     }
     $tpDiv.append($tpList);
-    // Store element offset.
-    var elmOffset = $(elm).offset();
     // Append the timPicker to the body and position it.
-    $tpDiv.appendTo('body').css({'top':elmOffset.top, 'left':elmOffset.left}).hide();
-    
-    $("li", $tpList).unbind().mouseover(function() {
-      $("li.selected", $tpDiv).removeClass("selected");  // TODO: only needs to run once.
-      $(this).addClass("selected");
+    $tpDiv.appendTo('body').hide();
+
+    // Store the mouse state, used by the blur event. Use mouseover instead of
+    // mousedown since Opera fires blur before mousedown.
+    $tpDiv.mouseover(function() {
+      tpOver = true;
+    }).mouseout(function() {
+      tpOver = false;
+    });
+
+    $("li", $tpList).mouseover(function() {
+      if (!keyDown) {
+        $(selectedSelector, $tpDiv).removeClass(selectedClass);
+        $(this).addClass(selectedClass);
+      }
     }).mousedown(function() {
        tpOver = true;
     }).click(function() {
       setTimeVal(elm, this, $tpDiv, settings);
       tpOver = false;
     });
-    
-    // Store ananymous function in variable since it's used twice.
+
     var showPicker = function() {
-                       var elmOffset = $(elm).offset();
-                       $tpDiv.css({'top':elmOffset.top, 'left':elmOffset.left}).show(); // Show picker.
-      $tpDiv.mouseover(function() { // Have to use mouseover instead of mousedown because of Opera
-        tpOver = true;
-      }).mouseout(function() {
-        tpOver = false;
-      });
-      $("li", $tpDiv).removeClass("selected");
-      
+      if ($tpDiv.is(":visible")) {
+        return false;
+      }
+      $("li", $tpDiv).removeClass(selectedClass);
+
+      // Position
+      var elmOffset = $(elm).offset();
+      $tpDiv.css({'top':elmOffset.top + elm.offsetHeight, 'left':elmOffset.left});
+
+      // Show picker. This has to be done before scrollTop is set since that
+      // can't be done on hidden elements.
+      $tpDiv.show();
+
       // Try to find a time in the list that matches the entered time.
-      var time = this.value ? timeStringToDate(this.value, settings) : startTime;
+      var time = elm.value ? timeStringToDate(elm.value, settings) : startTime;
       var startMin = startTime.getHours() * 60 + startTime.getMinutes();
       var min = (time.getHours() * 60 + time.getMinutes()) - startMin;
       var steps = Math.round(min / settings.step);
-      var roundTime = normaliseTime(new Date(2001, 0, 0, 0, (steps * settings.step + (startMin)), 0));
-      roundTime = (startTime < roundTime && roundTime < endTime) ? roundTime : startTime;
-      
+      var roundTime = normaliseTime(new Date(0, 0, 0, 0, (steps * settings.step + startMin), 0));
+      roundTime = (startTime < roundTime && roundTime <= endTime) ? roundTime : startTime;
       var $matchedTime = $("li:contains(" + formatTime(roundTime, settings) + ")", $tpDiv);
-      
+
       if ($matchedTime.length) {
-        $matchedTime.addClass("selected");
+        $matchedTime.addClass(selectedClass);
         // Scroll to matched time.
         $tpDiv[0].scrollTop = $matchedTime[0].offsetTop;
       }
+      return true;
     };
-    
-    $(elm).unbind().focus(showPicker).click(showPicker)
+    // Attach to click as well as focus so timePicker can be shown again when
+    // clicking on the input when it already has focus.
+    $(elm).focus(showPicker).click(showPicker);
     // Hide timepicker on blur
-    .blur(function() {
-      if (!tpOver && $tpDiv[0].parentNode) { // Don't remove when timePicker is clicked or when already removed
+    $(elm).blur(function() {
+      if (!tpOver) {
         $tpDiv.hide();
       }
-    })
-    
-    // Key support
-    .keypress(function(e) {
+    });
+    // Keypress doesn't repeat on Safari for non-text keys.
+    // Keydown doesn't repeat on Firefox and Opera on Mac.
+    // Using kepress for Opera and Firefox and keydown for the rest seems to
+    // work with up/down/enter/esc.
+    var event = ($.browser.opera || $.browser.mozilla) ? 'keypress' : 'keydown';
+    $(elm)[event](function(e) {
+      var $selected;
+      keyDown = true;
+      var top = $tpDiv[0].scrollTop;
       switch (e.keyCode) {
         case 38: // Up arrow.
-        case 63232: // Safari up arrow.
-          var $selected = $("li.selected", $tpList);
-          var prev = $selected.prev().addClass("selected")[0];
+          // Just show picker if it's hidden.
+          if (showPicker()) {
+            return false;
+          };
+          $selected = $(selectedSelector, $tpList);
+          var prev = $selected.prev().addClass(selectedClass)[0];
           if (prev) {
-            $selected.removeClass("selected");
-            $tpDiv[0].scrollTop = prev.offsetTop;
+            $selected.removeClass(selectedClass);
+            // Scroll item into view.
+            if (prev.offsetTop < top) {
+              $tpDiv[0].scrollTop = top - prev.offsetHeight;
+            }
+          }
+          else {
+            // Loop to next item.
+            $selected.removeClass(selectedClass);
+            prev = $("li:last", $tpList).addClass(selectedClass)[0];
+            $tpDiv[0].scrollTop = prev.offsetTop - prev.offsetHeight;
           }
           return false;
           break;
-        case 40: // Down arrow.
-        case 63233: // Safari down arrow.
-          var $selected = $("li.selected", $tpList);
-          var next = $selected.length ? $selected.next().addClass("selected")[0] : $("li:first").addClass("selected")[0];
+        case 40: // Down arrow, similar in behaviour to up arrow.
+          if (showPicker()) {
+            return false;
+          };
+          $selected = $(selectedSelector, $tpList);
+          var next = $selected.next().addClass(selectedClass)[0];
           if (next) {
-            $selected.removeClass("selected");
-            $tpDiv[0].scrollTop = next.offsetTop;
+            $selected.removeClass(selectedClass);
+            if (next.offsetTop + next.offsetHeight > top + $tpDiv[0].offsetHeight) {
+              $tpDiv[0].scrollTop = top + next.offsetHeight;
+            }
+          }
+          else {
+            $selected.removeClass(selectedClass);
+            next = $("li:first", $tpList).addClass(selectedClass)[0];
+            $tpDiv[0].scrollTop = 0;
           }
           return false;
           break;
         case 13: // Enter
-          if (!$tpDiv.is(":hidden")) {
-            var sel = $("li.selected", $tpList)[0];
+          if ($tpDiv.is(":visible")) {
+            var sel = $(selectedSelector, $tpList)[0];
             setTimeVal(elm, sel, $tpDiv, settings);
-            return false;
           }
+          return false;
+          break;
+        case 27: // Esc
+          $tpDiv.hide();
+          return false;
           break;
       }
+      return true;
+    });
+    $(elm).keyup(function(e) {
+      keyDown = false;
     });
-    
     // Helper function to get an inputs current time as Date object.
     // Returns a Date object.
     this.getTime = function() {
       return timeStringToDate(elm.value, settings);
     };
     // Helper function to set a time input.
-    // Takes a Date object.
+    // Takes a Date object or string.
     this.setTime = function(time) {
-      elm.value = formatTime(normaliseTime(time), settings);
+      elm.value = formatTime(timeToDate(time, settings), settings);
       // Trigger element's change events.
       $(elm).change();
     };
-    
-  }; // End fn;   
-  
+
+  }; // End fn;
+
   // Plugin defaults.
   $.fn.timePicker.defaults = {
     step:30,
     separator: ':',
     show24Hours: true
   };
-  
+
   // Private functions.
-  
+
   function setTimeVal(elm, sel, $tpDiv, settings) {
     // Update input field
     elm.value = $(sel).text();
     // Hide picker
     $tpDiv.hide();
   }
-  
+
   function formatTime(time, settings) {
     var h = time.getHours();
     var hours = settings.show24Hours ? h : (((h + 11) % 12) + 1);
     var minutes = time.getMinutes();
     return formatNumber(hours) + settings.separator + formatNumber(minutes) + (settings.show24Hours ? '' : ((h < 12) ? ' AM' : ' PM'));
   }
-  
-       function formatNumber(value) {
-               return (value < 10 ? '0' : '') + value;
-       }
-  
+
+  function formatNumber(value) {
+    return (value < 10 ? '0' : '') + value;
+  }
+
+  function timeToDate(input, settings) {
+    return (typeof input == 'object') ? normaliseTime(input) : timeStringToDate(input, settings);
+  }
+
   function timeStringToDate(input, settings) {
     if (input) {
       var array = input.split(settings.separator);
       var hours = parseFloat(array[0]);
       var minutes = parseFloat(array[1]);
+
+      // Convert AM/PM hour to 24-hour format.
+      if (!settings.show24Hours) {
+        if (hours === 12 && input.indexOf('AM') !== -1) {
+          hours = 0;
+        }
+        else if (hours !== 12 && input.indexOf('PM') !== -1) {
+          hours += 12;
+        }
+      }
       var time = new Date(0, 0, 0, hours, minutes, 0);
       return normaliseTime(time);
     }
     return null;
   }
-  
+
   /* Normalise time object to a common date. */
-       function normaliseTime(time) {
-               time.setFullYear(2001);
-               time.setMonth(0);
-               time.setDate(0);
-               return time;
-       }
-  
+  function normaliseTime(time) {
+    time.setFullYear(2001);
+    time.setMonth(0);
+    time.setDate(0);
+    return time;
+  }
+
 })(jQuery);