[Rt-commit] rt branch, 4.0/datetimepicker-ui, created. rt-4.0.2-116-gfbd5402

Alex Vandiver alexmv at bestpractical.com
Mon Jun 25 17:38:03 EDT 2012


The branch, 4.0/datetimepicker-ui has been created
        at  fbd54024abb01247fbc78febf10a7552cf7cd675 (commit)

- Log -----------------------------------------------------------------
commit d772292a40d661b493e115756025d38a7619d137
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Mon Sep 19 16:26:01 2011 -0400

    Refactor common datepicker options

diff --git a/share/html/NoAuth/js/util.js b/share/html/NoAuth/js/util.js
index b1a4a0b..87cb3f5 100644
--- a/share/html/NoAuth/js/util.js
+++ b/share/html/NoAuth/js/util.js
@@ -222,14 +222,12 @@ function doOnLoad( js ) {
 }
 
 jQuery(function() {
-    jQuery(".ui-datepicker:not(.withtime)").datepicker( {
-        dateFormat: 'yy-mm-dd',
-        constrainInput: false
-    } );
-
-    jQuery(".ui-datepicker.withtime").datepicker( {
+    var opts = {
         dateFormat: 'yy-mm-dd',
         constrainInput: false,
+    };
+    jQuery(".ui-datepicker:not(.withtime)").datepicker(opts);
+    jQuery(".ui-datepicker.withtime").datepicker( jQuery.extend({}, opts, {
         onSelect: function( dateText, inst ) {
             // trigger timepicker to get time
             var button = document.createElement('input');
@@ -250,7 +248,7 @@ jQuery(function() {
 
             jQuery(button).focus();
         }
-    } );
+    }) );
 });
 
 function textToHTML(value) {

commit b82fc5988f44264ea65bafd56751aacdd4a9539d
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Mon Sep 19 16:26:45 2011 -0400

    Easier date selection through datepicker options
    
    This enables selection of dates outside the current month, adds a
    shortcut for "today", and provides dropdowns for quickly changing the
    month or year.

diff --git a/share/html/NoAuth/js/util.js b/share/html/NoAuth/js/util.js
index 87cb3f5..346d457 100644
--- a/share/html/NoAuth/js/util.js
+++ b/share/html/NoAuth/js/util.js
@@ -225,6 +225,11 @@ jQuery(function() {
     var opts = {
         dateFormat: 'yy-mm-dd',
         constrainInput: false,
+        showButtonPanel: true,
+        changeMonth: true,
+        changeYear: true,
+        showOtherMonths: true,
+        selectOtherMonths: true
     };
     jQuery(".ui-datepicker:not(.withtime)").datepicker(opts);
     jQuery(".ui-datepicker.withtime").datepicker( jQuery.extend({}, opts, {

commit ec2725113db58a52527db7a35b9c134403cc9f90
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Thu Oct 13 16:49:47 2011 -0400

    Replace timepickr with a new one that is well integrated into the datepicker
    
    Sliders are used for the hour and minute, with a five minute step
    interval.  By hooking the slider widgets, we can fake stepping and still
    allow arbitrary, unconstrained input in the text field.

diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index 5e0a10c..59bd64a 100755
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -867,7 +867,7 @@ Set(@JSFiles, qw/
     jquery_noconflict.js
     jquery-ui-1.8.4.custom.min.js
     jquery-ui-patch-datepicker.js
-    ui.timepickr.js
+    jquery-ui-timepicker-addon.js
     titlebox-state.js
     util.js
     userautocomplete.js
diff --git a/share/html/NoAuth/css/base/jquery-ui-timepicker-addon.css b/share/html/NoAuth/css/base/jquery-ui-timepicker-addon.css
new file mode 100644
index 0000000..71e4c46
--- /dev/null
+++ b/share/html/NoAuth/css/base/jquery-ui-timepicker-addon.css
@@ -0,0 +1,6 @@
+.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
+.ui-timepicker-div dl { text-align: left; }
+.ui-timepicker-div dl dt { height: 25px; }
+.ui-timepicker-div dl dd { margin: -25px 10px 10px 65px; }
+.ui-timepicker-div td { font-size: 90%; }
+.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
diff --git a/share/html/NoAuth/css/base/jquery-ui.css b/share/html/NoAuth/css/base/jquery-ui.css
index 09d30c4..b2cf695 100644
--- a/share/html/NoAuth/css/base/jquery-ui.css
+++ b/share/html/NoAuth/css/base/jquery-ui.css
@@ -46,5 +46,3 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 @import "jquery-ui.custom.modified.css";
- at import "ui.timepickr.css";
- at import "ui.timepickr.custom.css";
diff --git a/share/html/NoAuth/css/base/jquery-ui.custom.modified.css b/share/html/NoAuth/css/base/jquery-ui.custom.modified.css
index 7a32322..3b1e1a0 100644
--- a/share/html/NoAuth/css/base/jquery-ui.custom.modified.css
+++ b/share/html/NoAuth/css/base/jquery-ui.custom.modified.css
@@ -452,3 +452,27 @@
     width: 200px; /*must have*/
     height: 200px; /*must have*/
 }
+/*
+ * jQuery UI Slider 1.8.4
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider#theming
+ */
+.ui-slider { position: relative; text-align: left; }
+.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
+.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
+
+.ui-slider-horizontal { height: .8em; }
+.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
+.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
+.ui-slider-horizontal .ui-slider-range-min { left: 0; }
+.ui-slider-horizontal .ui-slider-range-max { right: 0; }
+
+.ui-slider-vertical { width: .8em; height: 100px; }
+.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
+.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
+.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
+.ui-slider-vertical .ui-slider-range-max { top: 0; }
diff --git a/share/html/NoAuth/css/base/main.css b/share/html/NoAuth/css/base/main.css
index 5bb3098..80facd5 100644
--- a/share/html/NoAuth/css/base/main.css
+++ b/share/html/NoAuth/css/base/main.css
@@ -49,6 +49,7 @@
 
 @import "yui-fonts.css";
 @import "jquery-ui.css";
+ at import "jquery-ui-timepicker-addon.css";
 @import "superfish.css";
 @import "superfish-navbar.css";
 @import "superfish-vertical.css";
diff --git a/share/html/NoAuth/css/base/ui.timepickr.css b/share/html/NoAuth/css/base/ui.timepickr.css
deleted file mode 100644
index e2dacf7..0000000
--- a/share/html/NoAuth/css/base/ui.timepickr.css
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-  jQuery ui.timepickr
-  http://code.google.com/p/jquery-utils/
-
-  copyright Maxime Haineault <haineault at gmail.com> 
-  http://haineault.com
-
-  MIT License (http://www.opensource.org/licenses/mit-license.php
-*/
-.ui-timepickr {
-    position:absolute;
-    width:480px; 
-}
-
-.ui-timepickr-row {
-    margin:0;
-    padding:0;
-    margin-top:2px; 
-    display:none;
-    position:relative;
-}
-
-.ui-timepickr-button {
-    float:left;
-    margin:0;
-    padding:0;
-    list-style:none;
-    list-style-type:none;
-}
-
-.ui-timepickr-button span {
-    font-size:.7em;
-    padding:4px 6px 4px 6px;
-    margin-left:2px;
-    text-align:center;
-    cursor:pointer;
-    display:block;
-    text-align:center;
-
-
-    /* system theme (default) */
-    border-width:1px;
-    border-style:solid;
-    /*border-color:ThreeDLightShadow ThreeDShadow ThreeDShadow ThreeDLightShadow;
-    color:ButtonText;
-    background:ButtonFace;*/
-}
-
-.ui-timepickr-button span.ui-state-hover {
-    /*color:HighlightText;
-    background:Highlight;*/
-}
-
-.ui-state-hover span {
-    /*background:#c30;*/
-}
diff --git a/share/html/NoAuth/css/base/ui.timepickr.custom.css b/share/html/NoAuth/css/base/ui.timepickr.custom.css
deleted file mode 100644
index 35bfa62..0000000
--- a/share/html/NoAuth/css/base/ui.timepickr.custom.css
+++ /dev/null
@@ -1,54 +0,0 @@
-%# BEGIN BPS TAGGED BLOCK {{{
-%#
-%# COPYRIGHT:
-%#
-%# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
-%#                                          <sales at bestpractical.com>
-%#
-%# (Except where explicitly superseded by other copyright notices)
-%#
-%#
-%# LICENSE:
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-%# General Public License for more details.
-%#
-%# You should have received a copy of the GNU General Public License
-%# along with this program; if not, write to the Free Software
-%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-%# 02110-1301 or visit their web page on the internet at
-%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
-%#
-%#
-%# CONTRIBUTION SUBMISSION POLICY:
-%#
-%# (The following paragraph is not intended to limit the rights granted
-%# to you to modify and distribute this software under the terms of
-%# the GNU General Public License and is only of importance to you if
-%# you choose to contribute your changes and enhancements to the
-%# community by submitting them to Best Practical Solutions, LLC.)
-%#
-%# By intentionally submitting any modifications, corrections or
-%# derivatives to this work, or any other work intended for use with
-%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-%# you are the copyright holder for those contributions and you grant
-%# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
-%# royalty-free, perpetual, license to use, copy, create derivative
-%# works based on those contributions, and sublicense and distribute
-%# those contributions and any derivatives thereof.
-%#
-%# END BPS TAGGED BLOCK }}}
-.ui-timepickr {
-    font-size: 1.1em;
-}
-
-.ui-timepickr-button span {
-    background: white;
-}
diff --git a/share/html/NoAuth/js/jquery-ui-1.8.4.custom.min.js b/share/html/NoAuth/js/jquery-ui-1.8.4.custom.min.js
index e90b4fe..990bb75 100644
--- a/share/html/NoAuth/js/jquery-ui-1.8.4.custom.min.js
+++ b/share/html/NoAuth/js/jquery-ui-1.8.4.custom.min.js
@@ -222,3 +222,53 @@ c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(t
 function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));
 return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new L;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.4";window["DP_jQuery_"+y]=d})(jQuery);
 ;
+/*!
+ * jQuery UI Mouse 1.8.4
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Mouse
+ *
+ * Depends:
+ *	jquery.ui.widget.js
+ */
+(function(c){c.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(b){return a._mouseDown(b)}).bind("click."+this.widgetName,function(b){if(a._preventClickEvent){a._preventClickEvent=false;b.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&
+this._mouseUp(a);this._mouseDownEvent=a;var b=this,e=a.which==1,f=typeof this.options.cancel=="string"?c(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){b.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();
+return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._mouseUpDelegate=function(d){return b._mouseUp(d)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);c.browser.safari||a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(c.browser.msie&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);return a.preventDefault()}if(this._mouseDistanceMet(a)&&
+this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;this._preventClickEvent=a.target==this._mouseDownEvent.target;this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-
+a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
+/*
+ * jQuery UI Slider 1.8.4
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider
+ *
+ * Depends:
+ *  jquery.ui.core.js
+ *  jquery.ui.mouse.js
+ *  jquery.ui.widget.js
+ */
+(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var a=this,b=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");b.disabled&&this.element.addClass("ui-slider-disabled ui-disabled");
+this.range=d([]);if(b.range){if(b.range===true){this.range=d("<div></div>");if(!b.values)b.values=[this._valueMin(),this._valueMin()];if(b.values.length&&b.values.length!==2)b.values=[b.values[0],b.values[0]]}else this.range=d("<div></div>");this.range.appendTo(this.element).addClass("ui-slider-range");if(b.range==="min"||b.range==="max")this.range.addClass("ui-slider-range-"+b.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");
+if(b.values&&b.values.length)for(;d(".ui-slider-handle",this.element).length<b.values.length;)d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){b.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(b.disabled)d(this).blur();
+else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),h,g,i;if(!a.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e=
+false;if(!a._keySliding){a._keySliding=true;d(this).addClass("ui-state-active");h=a._start(c,f);if(h===false)return}break}i=a.options.step;h=a.options.values&&a.options.values.length?(g=a.values(f)):(g=a.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=a._valueMin();break;case d.ui.keyCode.END:g=a._valueMax();break;case d.ui.keyCode.PAGE_UP:g=a._trimAlignValue(h+(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=a._trimAlignValue(h-(a._valueMax()-a._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h===
+a._valueMax())return;g=a._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===a._valueMin())return;g=a._trimAlignValue(h-i);break}a._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(a._keySliding){a._keySliding=false;a._stop(c,e);a._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");
+this._mouseDestroy();return this},_mouseCapture:function(a){var b=this.options,c,e,f,h,g;if(b.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:a.pageX,y:a.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(b.range===true&&this.values(1)===b.min){g+=1;f=d(this.handles[g])}if(this._start(a,
+g)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass("ui-state-active").focus();b=f.offset();this._clickOffset=!d(a.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:a.pageX-b.left-f.width()/2,top:a.pageY-b.top-f.height()/2-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};this._slide(a,g,c);return this._animateOff=true},_mouseStart:function(){return true},_mouseDrag:function(a){var b=
+this._normValueFromMouse({x:a.pageX,y:a.pageY});this._slide(a,this._handleIndex,b);return false},_mouseStop:function(a){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(a,this._handleIndex);this._change(a,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(a){var b;if(this.orientation==="horizontal"){b=
+this.elementSize.width;a=a.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{b=this.elementSize.height;a=a.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}b=a/b;if(b>1)b=1;if(b<0)b=0;if(this.orientation==="vertical")b=1-b;a=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+b*a)},_start:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);
+c.values=this.values()}return this._trigger("start",a,c)},_slide:function(a,b,c){var e;if(this.options.values&&this.options.values.length){e=this.values(b?0:1);if(this.options.values.length===2&&this.options.range===true&&(b===0&&c>e||b===1&&c<e))c=e;if(c!==this.values(b)){e=this.values();e[b]=c;a=this._trigger("slide",a,{handle:this.handles[b],value:c,values:e});this.values(b?0:1);a!==false&&this.values(b,c,true)}}else if(c!==this.value()){a=this._trigger("slide",a,{handle:this.handles[b],value:c});
+a!==false&&this.value(c)}},_stop:function(a,b){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);c.values=this.values()}this._trigger("stop",a,c)},_change:function(a,b){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[b],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(b);c.values=this.values()}this._trigger("change",a,c)}},value:function(a){if(arguments.length){this.options.value=
+this._trimAlignValue(a);this._refreshValue();this._change(null,0)}return this._value()},values:function(a,b){var c,e,f;if(arguments.length>1){this.options.values[a]=this._trimAlignValue(b);this._refreshValue();this._change(null,a)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f<c.length;f+=1){c[f]=this._trimAlignValue(e[f]);this._change(null,f)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(a):this.value();
+else return this._values()},_setOption:function(a,b){var c,e=0;if(d.isArray(this.options.values))e=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(a){case "disabled":if(b){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation();
+this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<e;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var a=this.options.value;return a=this._trimAlignValue(a)},_values:function(a){var b,c;if(arguments.length){b=this.options.values[a];
+return b=this._trimAlignValue(b)}else{b=this.options.values.slice();for(c=0;c<b.length;c+=1)b[c]=this._trimAlignValue(b[c]);return b}},_trimAlignValue:function(a){if(a<this._valueMin())return this._valueMin();if(a>this._valueMax())return this._valueMax();var b=this.options.step>0?this.options.step:1,c=a%b;a=a-c;if(Math.abs(c)*2>=b)a+=c>0?b:-b;return parseFloat(a.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var a=
+this.options.range,b=this.options,c=this,e=!this._animateOff?b.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](h,b.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(k===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},b.animate);if(k===1)c.range[e?"animate":"css"]({width:f-
+g+"%"},{queue:false,duration:b.animate})}else{if(k===0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},b.animate);if(k===1)c.range[e?"animate":"css"]({height:f-g+"%"},{queue:false,duration:b.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](h,b.animate);if(a==="min"&&this.orientation==="horizontal")this.range.stop(1,1)[e?"animate":"css"]({width:f+"%"},
+b.animate);if(a==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-f+"%"},{queue:false,duration:b.animate});if(a==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},b.animate);if(a==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:b.animate})}}});d.extend(d.ui.slider,{version:"1.8.4"})})(jQuery);
diff --git a/share/html/NoAuth/js/jquery-ui-timepicker-addon.js b/share/html/NoAuth/js/jquery-ui-timepicker-addon.js
new file mode 100644
index 0000000..ec4b577
--- /dev/null
+++ b/share/html/NoAuth/js/jquery-ui-timepicker-addon.js
@@ -0,0 +1,1275 @@
+/*
+* jQuery timepicker addon
+* By: Trent Richardson [http://trentrichardson.com]
+* Version 0.9.7
+* Last Modified: 10/02/2011
+* 
+* Copyright 2011 Trent Richardson
+* Dual licensed under the MIT and GPL licenses.
+* http://trentrichardson.com/Impromptu/GPL-LICENSE.txt
+* http://trentrichardson.com/Impromptu/MIT-LICENSE.txt
+* 
+* HERES THE CSS:
+* .ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
+* .ui-timepicker-div dl { text-align: left; }
+* .ui-timepicker-div dl dt { height: 25px; }
+* .ui-timepicker-div dl dd { margin: -25px 10px 10px 65px; }
+* .ui-timepicker-div td { font-size: 90%; }
+* .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
+*/
+
+(function($) {
+
+$.extend($.ui, { timepicker: { version: "0.9.7" } });
+
+/* Time picker manager.
+   Use the singleton instance of this class, $.timepicker, to interact with the time picker.
+   Settings for (groups of) time pickers are maintained in an instance object,
+   allowing multiple different settings on the same page. */
+
+function Timepicker() {
+	this.regional = []; // Available regional settings, indexed by language code
+	this.regional[''] = { // Default regional settings
+		currentText: 'Now',
+		closeText: 'Done',
+		ampm: false,
+		amNames: ['AM', 'A'],
+		pmNames: ['PM', 'P'],
+		timeFormat: 'hh:mm tt',
+		timeSuffix: '',
+		timeOnlyTitle: 'Choose Time',
+		timeText: 'Time',
+		hourText: 'Hour',
+		minuteText: 'Minute',
+		secondText: 'Second',
+		millisecText: 'Millisecond',
+		timezoneText: 'Time Zone'
+	};
+	this._defaults = { // Global defaults for all the datetime picker instances
+		showButtonPanel: true,
+		timeOnly: false,
+		showHour: true,
+		showMinute: true,
+		showSecond: false,
+		showMillisec: false,
+		showTimezone: false,
+		showTime: true,
+		stepHour: 0.05,
+		stepMinute: 0.05,
+		stepSecond: 0.05,
+		stepMillisec: 0.5,
+		hour: 0,
+		minute: 0,
+		second: 0,
+		millisec: 0,
+		timezone: '+0000',
+		hourMin: 0,
+		minuteMin: 0,
+		secondMin: 0,
+		millisecMin: 0,
+		hourMax: 23,
+		minuteMax: 59,
+		secondMax: 59,
+		millisecMax: 999,
+		minDateTime: null,
+		maxDateTime: null,
+		onSelect: null,
+		hourGrid: 0,
+		minuteGrid: 0,
+		secondGrid: 0,
+		millisecGrid: 0,
+		alwaysSetTime: true,
+		separator: ' ',
+		altFieldTimeOnly: true,
+		showTimepicker: true,
+		timezoneIso8609: false,
+		timezoneList: null
+	};
+	$.extend(this._defaults, this.regional['']);
+}
+
+$.extend(Timepicker.prototype, {
+	$input: null,
+	$altInput: null,
+	$timeObj: null,
+	inst: null,
+	hour_slider: null,
+	minute_slider: null,
+	second_slider: null,
+	millisec_slider: null,
+	timezone_select: null,
+	hour: 0,
+	minute: 0,
+	second: 0,
+	millisec: 0,
+	timezone: '+0000',
+	hourMinOriginal: null,
+	minuteMinOriginal: null,
+	secondMinOriginal: null,
+	millisecMinOriginal: null,
+	hourMaxOriginal: null,
+	minuteMaxOriginal: null,
+	secondMaxOriginal: null,
+	millisecMaxOriginal: null,
+	ampm: '',
+	formattedDate: '',
+	formattedTime: '',
+	formattedDateTime: '',
+	timezoneList: null,
+
+	/* Override the default settings for all instances of the time picker.
+	   @param  settings  object - the new settings to use as defaults (anonymous object)
+	   @return the manager object */
+	setDefaults: function(settings) {
+		extendRemove(this._defaults, settings || {});
+		return this;
+	},
+
+	//########################################################################
+	// Create a new Timepicker instance
+	//########################################################################
+	_newInst: function($input, o) {
+		var tp_inst = new Timepicker(),
+			inlineSettings = {};
+			
+		for (var attrName in this._defaults) {
+			var attrValue = $input.attr('time:' + attrName);
+			if (attrValue) {
+				try {
+					inlineSettings[attrName] = eval(attrValue);
+				} catch (err) {
+					inlineSettings[attrName] = attrValue;
+				}
+			}
+		}
+		tp_inst._defaults = $.extend({}, this._defaults, inlineSettings, o, {
+			beforeShow: function(input, dp_inst) {
+				if ($.isFunction(o.beforeShow))
+					o.beforeShow(input, dp_inst, tp_inst);
+			},
+			onChangeMonthYear: function(year, month, dp_inst) {
+				// Update the time as well : this prevents the time from disappearing from the $input field.
+				tp_inst._updateDateTime(dp_inst);
+				if ($.isFunction(o.onChangeMonthYear))
+					o.onChangeMonthYear.call($input[0], year, month, dp_inst, tp_inst);
+			},
+			onClose: function(dateText, dp_inst) {
+				if (tp_inst.timeDefined === true && $input.val() != '')
+					tp_inst._updateDateTime(dp_inst);
+				if ($.isFunction(o.onClose))
+					o.onClose.call($input[0], dateText, dp_inst, tp_inst);
+			},
+			timepicker: tp_inst // add timepicker as a property of datepicker: $.datepicker._get(dp_inst, 'timepicker');
+		});
+		tp_inst.amNames = $.map(tp_inst._defaults.amNames, function(val) { return val.toUpperCase() });
+		tp_inst.pmNames = $.map(tp_inst._defaults.pmNames, function(val) { return val.toUpperCase() });
+
+		if (tp_inst._defaults.timezoneList === null) {
+			var timezoneList = [];
+			for (var i = -11; i <= 12; i++)
+				timezoneList.push((i >= 0 ? '+' : '-') + ('0' + Math.abs(i).toString()).slice(-2) + '00');
+			if (tp_inst._defaults.timezoneIso8609)
+				timezoneList = $.map(timezoneList, function(val) {
+					return val == '+0000' ? 'Z' : (val.substring(0, 3) + ':' + val.substring(3));
+				});
+			tp_inst._defaults.timezoneList = timezoneList;
+		}
+
+		tp_inst.hour = tp_inst._defaults.hour;
+		tp_inst.minute = tp_inst._defaults.minute;
+		tp_inst.second = tp_inst._defaults.second;
+		tp_inst.millisec = tp_inst._defaults.millisec;
+		tp_inst.ampm = '';
+		tp_inst.$input = $input;
+
+		if (o.altField)
+			tp_inst.$altInput = $(o.altField)
+				.css({ cursor: 'pointer' })
+				.focus(function(){ $input.trigger("focus"); });
+		
+		if(tp_inst._defaults.minDate==0 || tp_inst._defaults.minDateTime==0)
+		{
+			tp_inst._defaults.minDate=new Date();
+		}
+		if(tp_inst._defaults.maxDate==0 || tp_inst._defaults.maxDateTime==0)
+		{
+			tp_inst._defaults.maxDate=new Date();
+		}
+		
+		// datepicker needs minDate/maxDate, timepicker needs minDateTime/maxDateTime..
+		if(tp_inst._defaults.minDate !== undefined && tp_inst._defaults.minDate instanceof Date)
+			tp_inst._defaults.minDateTime = new Date(tp_inst._defaults.minDate.getTime());
+		if(tp_inst._defaults.minDateTime !== undefined && tp_inst._defaults.minDateTime instanceof Date)
+			tp_inst._defaults.minDate = new Date(tp_inst._defaults.minDateTime.getTime());
+		if(tp_inst._defaults.maxDate !== undefined && tp_inst._defaults.maxDate instanceof Date)
+			tp_inst._defaults.maxDateTime = new Date(tp_inst._defaults.maxDate.getTime());
+		if(tp_inst._defaults.maxDateTime !== undefined && tp_inst._defaults.maxDateTime instanceof Date)
+			tp_inst._defaults.maxDate = new Date(tp_inst._defaults.maxDateTime.getTime());
+		return tp_inst;
+	},
+
+	//########################################################################
+	// add our sliders to the calendar
+	//########################################################################
+	_addTimePicker: function(dp_inst) {
+		var currDT = (this.$altInput && this._defaults.altFieldTimeOnly) ?
+				this.$input.val() + ' ' + this.$altInput.val() : 
+				this.$input.val();
+
+		this.timeDefined = this._parseTime(currDT);
+		this._limitMinMaxDateTime(dp_inst, false);
+		this._injectTimePicker();
+	},
+
+	//########################################################################
+	// parse the time string from input value or _setTime
+	//########################################################################
+	_parseTime: function(timeString, withDate) {
+		var regstr = this._defaults.timeFormat.toString()
+				.replace(/h{1,2}/ig, '(\\d?\\d)')
+				.replace(/m{1,2}/ig, '(\\d?\\d)')
+				.replace(/s{1,2}/ig, '(\\d?\\d)')
+				.replace(/l{1}/ig, '(\\d?\\d?\\d)')
+				.replace(/t{1,2}/ig, this._getPatternAmpm())
+				.replace(/z{1}/ig, '(z|[-+]\\d\\d:?\\d\\d)?')
+				.replace(/\s/g, '\\s?') + this._defaults.timeSuffix + '$',
+			order = this._getFormatPositions(),
+			ampm = '',
+			treg;
+
+		if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]);
+
+		if (withDate || !this._defaults.timeOnly) {
+			// the time should come after x number of characters and a space.
+			// x = at least the length of text specified by the date format
+			var dp_dateFormat = $.datepicker._get(this.inst, 'dateFormat');
+			// escape special regex characters in the seperator
+			var specials = new RegExp("[.*+?|()\\[\\]{}\\\\]", "g");
+			regstr = '.{' + dp_dateFormat.length + ',}' + this._defaults.separator.replace(specials, "\\$&") + regstr;
+		}
+		
+		treg = timeString.match(new RegExp(regstr, 'i'));
+
+		if (treg) {
+			if (order.t !== -1) {
+				if (treg[order.t] === undefined || treg[order.t].length === 0) {
+					ampm = '';
+					this.ampm = '';
+				} else {
+					ampm = $.inArray(treg[order.t].toUpperCase(), this.amNames) !== -1 ? 'AM' : 'PM';
+					this.ampm = this._defaults[ampm == 'AM' ? 'amNames' : 'pmNames'][0];
+				}
+			}
+
+			if (order.h !== -1) {
+				if (ampm == 'AM' && treg[order.h] == '12')
+					this.hour = 0; // 12am = 0 hour
+				else if (ampm == 'PM' && treg[order.h] != '12')
+					this.hour = (parseFloat(treg[order.h]) + 12).toFixed(0); // 12pm = 12 hour, any other pm = hour + 12
+				else this.hour = Number(treg[order.h]);
+			}
+
+			if (order.m !== -1) this.minute = Number(treg[order.m]);
+			if (order.s !== -1) this.second = Number(treg[order.s]);
+			if (order.l !== -1) this.millisec = Number(treg[order.l]);
+			if (order.z !== -1 && treg[order.z] !== undefined) {
+				var tz = treg[order.z].toUpperCase();
+				switch (tz.length) {
+				case 1:	// Z
+					tz = this._defaults.timezoneIso8609 ? 'Z' : '+0000';
+					break;
+				case 5:	// +hhmm
+					if (this._defaults.timezoneIso8609)
+						tz = tz.substring(1) == '0000'
+						   ? 'Z'
+						   : tz.substring(0, 3) + ':' + tz.substring(3);
+					break;
+				case 6:	// +hh:mm
+					if (!this._defaults.timezoneIso8609)
+						tz = tz == 'Z' || tz.substring(1) == '00:00'
+						   ? '+0000'
+						   : tz.replace(/:/, '');
+					else if (tz.substring(1) == '00:00')
+						tz = 'Z';
+					break;
+				}
+				this.timezone = tz;
+			}
+			
+			return true;
+
+		}
+		return false;
+	},
+
+	//########################################################################
+	// pattern for standard and localized AM/PM markers
+	//########################################################################
+	_getPatternAmpm: function() {
+		var markers = [];
+			o = this._defaults;
+		if (o.amNames)
+			$.merge(markers, o.amNames);
+		if (o.pmNames)
+			$.merge(markers, o.pmNames);
+		markers = $.map(markers, function(val) { return val.replace(/[.*+?|()\[\]{}\\]/g, '\\$&') });
+		return '(' + markers.join('|') + ')?';
+	},
+
+	//########################################################################
+	// figure out position of time elements.. cause js cant do named captures
+	//########################################################################
+	_getFormatPositions: function() {
+		var finds = this._defaults.timeFormat.toLowerCase().match(/(h{1,2}|m{1,2}|s{1,2}|l{1}|t{1,2}|z)/g),
+			orders = { h: -1, m: -1, s: -1, l: -1, t: -1, z: -1 };
+
+		if (finds)
+			for (var i = 0; i < finds.length; i++)
+				if (orders[finds[i].toString().charAt(0)] == -1)
+					orders[finds[i].toString().charAt(0)] = i + 1;
+
+		return orders;
+	},
+
+	//########################################################################
+	// generate and inject html for timepicker into ui datepicker
+	//########################################################################
+	_injectTimePicker: function() {
+		var $dp = this.inst.dpDiv,
+			o = this._defaults,
+			tp_inst = this,
+			// Added by Peter Medeiros:
+			// - Figure out what the hour/minute/second max should be based on the step values.
+			// - Example: if stepMinute is 15, then minMax is 45.
+			hourMax = (o.hourMax - ((o.hourMax - o.hourMin) % o.stepHour)).toFixed(0),
+            minMax  = (o.minuteMax - ((o.minuteMax - o.minuteMin) % o.stepMinute)).toFixed(0),
+            secMax  = (o.secondMax - ((o.secondMax - o.secondMin) % o.stepSecond)).toFixed(0),
+			millisecMax  = (o.millisecMax - ((o.millisecMax - o.millisecMin) % o.stepMillisec)).toFixed(0),
+			dp_id = this.inst.id.toString().replace(/([^A-Za-z0-9_])/g, '');
+
+		// Prevent displaying twice
+		//if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0) {
+		if ($dp.find("div#ui-timepicker-div-"+ dp_id).length === 0 && o.showTimepicker) {
+			var noDisplay = ' style="display:none;"',
+				html =	'<div class="ui-timepicker-div" id="ui-timepicker-div-' + dp_id + '"><dl>' +
+						'<dt class="ui_tpicker_time_label" id="ui_tpicker_time_label_' + dp_id + '"' +
+						((o.showTime) ? '' : noDisplay) + '>' + o.timeText + '</dt>' +
+						'<dd class="ui_tpicker_time" id="ui_tpicker_time_' + dp_id + '"' +
+						((o.showTime) ? '' : noDisplay) + '></dd>' +
+						'<dt class="ui_tpicker_hour_label" id="ui_tpicker_hour_label_' + dp_id + '"' +
+						((o.showHour) ? '' : noDisplay) + '>' + o.hourText + '</dt>',
+				hourGridSize = 0,
+				minuteGridSize = 0,
+				secondGridSize = 0,
+				millisecGridSize = 0,
+				size;
+
+ 			// Hours
+			if (o.showHour && o.hourGrid > 0) {
+				html += '<dd class="ui_tpicker_hour">' +
+						'<div id="ui_tpicker_hour_' + dp_id + '"' + ((o.showHour)   ? '' : noDisplay) + '></div>' +
+						'<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
+
+				for (var h = o.hourMin; h <= hourMax; h += parseInt(o.hourGrid,10)) {
+					hourGridSize++;
+					var tmph = (o.ampm && h > 12) ? h-12 : h;
+					if (tmph < 10) tmph = '0' + tmph;
+					if (o.ampm) {
+						if (h == 0) tmph = 12 +'a';
+						else if (h < 12) tmph += 'a';
+						else tmph += 'p';
+					}
+					html += '<td>' + tmph + '</td>';
+				}
+
+				html += '</tr></table></div>' +
+						'</dd>';
+			} else html += '<dd class="ui_tpicker_hour" id="ui_tpicker_hour_' + dp_id + '"' +
+							((o.showHour) ? '' : noDisplay) + '></dd>';
+
+			html += '<dt class="ui_tpicker_minute_label" id="ui_tpicker_minute_label_' + dp_id + '"' +
+					((o.showMinute) ? '' : noDisplay) + '>' + o.minuteText + '</dt>';
+
+			// Minutes
+			if (o.showMinute && o.minuteGrid > 0) {
+				html += '<dd class="ui_tpicker_minute ui_tpicker_minute_' + o.minuteGrid + '">' +
+						'<div id="ui_tpicker_minute_' + dp_id + '"' +
+						((o.showMinute) ? '' : noDisplay) + '></div>' +
+						'<div style="padding-left: 1px"><table class="ui-tpicker-grid-label"><tr>';
+
+				for (var m = o.minuteMin; m <= minMax; m += parseInt(o.minuteGrid,10)) {
+					minuteGridSize++;
+					html += '<td>' + ((m < 10) ? '0' : '') + m + '</td>';
+				}
+
+				html += '</tr></table></div>' +
+						'</dd>';
+			} else html += '<dd class="ui_tpicker_minute" id="ui_tpicker_minute_' + dp_id + '"' +
+							((o.showMinute) ? '' : noDisplay) + '></dd>';
+
+			// Seconds
+			html += '<dt class="ui_tpicker_second_label" id="ui_tpicker_second_label_' + dp_id + '"' +
+					((o.showSecond) ? '' : noDisplay) + '>' + o.secondText + '</dt>';
+
+			if (o.showSecond && o.secondGrid > 0) {
+				html += '<dd class="ui_tpicker_second ui_tpicker_second_' + o.secondGrid + '">' +
+						'<div id="ui_tpicker_second_' + dp_id + '"' +
+						((o.showSecond) ? '' : noDisplay) + '></div>' +
+						'<div style="padding-left: 1px"><table><tr>';
+
+				for (var s = o.secondMin; s <= secMax; s += parseInt(o.secondGrid,10)) {
+					secondGridSize++;
+					html += '<td>' + ((s < 10) ? '0' : '') + s + '</td>';
+				}
+
+				html += '</tr></table></div>' +
+						'</dd>';
+			} else html += '<dd class="ui_tpicker_second" id="ui_tpicker_second_' + dp_id + '"'	+
+							((o.showSecond) ? '' : noDisplay) + '></dd>';
+
+			// Milliseconds
+			html += '<dt class="ui_tpicker_millisec_label" id="ui_tpicker_millisec_label_' + dp_id + '"' +
+					((o.showMillisec) ? '' : noDisplay) + '>' + o.millisecText + '</dt>';
+
+			if (o.showMillisec && o.millisecGrid > 0) {
+				html += '<dd class="ui_tpicker_millisec ui_tpicker_millisec_' + o.millisecGrid + '">' +
+						'<div id="ui_tpicker_millisec_' + dp_id + '"' +
+						((o.showMillisec) ? '' : noDisplay) + '></div>' +
+						'<div style="padding-left: 1px"><table><tr>';
+
+				for (var l = o.millisecMin; l <= millisecMax; l += parseInt(o.millisecGrid,10)) {
+					millisecGridSize++;
+					html += '<td>' + ((l < 10) ? '0' : '') + s + '</td>';
+				}
+
+				html += '</tr></table></div>' +
+						'</dd>';
+			} else html += '<dd class="ui_tpicker_millisec" id="ui_tpicker_millisec_' + dp_id + '"'	+
+							((o.showMillisec) ? '' : noDisplay) + '></dd>';
+
+			// Timezone
+			html += '<dt class="ui_tpicker_timezone_label" id="ui_tpicker_timezone_label_' + dp_id + '"' +
+					((o.showTimezone) ? '' : noDisplay) + '>' + o.timezoneText + '</dt>';
+			html += '<dd class="ui_tpicker_timezone" id="ui_tpicker_timezone_' + dp_id + '"'	+
+							((o.showTimezone) ? '' : noDisplay) + '></dd>';
+
+			html += '</dl></div>';
+			$tp = $(html);
+
+				// if we only want time picker...
+			if (o.timeOnly === true) {
+				$tp.prepend(
+					'<div class="ui-widget-header ui-helper-clearfix ui-corner-all">' +
+						'<div class="ui-datepicker-title">' + o.timeOnlyTitle + '</div>' +
+					'</div>');
+				$dp.find('.ui-datepicker-header, .ui-datepicker-calendar').hide();
+			}
+
+			this.hour_slider = $tp.find('#ui_tpicker_hour_'+ dp_id).slider({
+				orientation: "horizontal",
+				value: this.hour,
+				min: o.hourMin,
+				max: hourMax,
+				step: o.stepHour,
+				slide: function(event, ui) {
+					tp_inst.hour_slider.slider( "option", "value", ui.value);
+					tp_inst._onTimeChange();
+				}
+			});
+
+			// Updated by Peter Medeiros:
+			// - Pass in Event and UI instance into slide function
+			this.minute_slider = $tp.find('#ui_tpicker_minute_'+ dp_id).slider({
+				orientation: "horizontal",
+				value: this.minute,
+				min: o.minuteMin,
+				max: minMax,
+				step: o.stepMinute,
+				slide: function(event, ui) {
+					// update the global minute slider instance value with the current slider value
+					tp_inst.minute_slider.slider( "option", "value", ui.value);
+					tp_inst._onTimeChange();
+				}
+			});
+
+			this.second_slider = $tp.find('#ui_tpicker_second_'+ dp_id).slider({
+				orientation: "horizontal",
+				value: this.second,
+				min: o.secondMin,
+				max: secMax,
+				step: o.stepSecond,
+				slide: function(event, ui) {
+					tp_inst.second_slider.slider( "option", "value", ui.value);
+					tp_inst._onTimeChange();
+				}
+			});
+
+			this.millisec_slider = $tp.find('#ui_tpicker_millisec_'+ dp_id).slider({
+				orientation: "horizontal",
+				value: this.millisec,
+				min: o.millisecMin,
+				max: millisecMax,
+				step: o.stepMillisec,
+				slide: function(event, ui) {
+					tp_inst.millisec_slider.slider( "option", "value", ui.value);
+					tp_inst._onTimeChange();
+				}
+			});
+
+			this.timezone_select = $tp.find('#ui_tpicker_timezone_'+ dp_id).append('<select></select>').find("select");
+			$.fn.append.apply(this.timezone_select,
+				$.map(o.timezoneList, function(val, idx) {
+					return $("<option />")
+						.val(typeof val == "object" ? val.value : val)
+						.text(typeof val == "object" ? val.label : val);
+				})
+			);
+			this.timezone_select.val((typeof this.timezone != "undefined" && this.timezone != null && this.timezone != "") ? this.timezone : o.timezone);
+			this.timezone_select.change(function() {
+				tp_inst._onTimeChange();
+			});
+
+			// Add grid functionality
+			if (o.showHour && o.hourGrid > 0) {
+				size = 100 * hourGridSize * o.hourGrid / (hourMax - o.hourMin);
+
+				$tp.find(".ui_tpicker_hour table").css({
+					width: size + "%",
+					marginLeft: (size / (-2 * hourGridSize)) + "%",
+					borderCollapse: 'collapse'
+				}).find("td").each( function(index) {
+					$(this).click(function() {
+						var h = $(this).html();
+						if(o.ampm)	{
+							var ap = h.substring(2).toLowerCase(),
+								aph = parseInt(h.substring(0,2), 10);
+							if (ap == 'a') {
+								if (aph == 12) h = 0;
+								else h = aph;
+							} else if (aph == 12) h = 12;
+							else h = aph + 12;
+						}
+						tp_inst.hour_slider.slider("option", "value", h);
+						tp_inst._onTimeChange();
+						tp_inst._onSelectHandler();
+					}).css({
+						cursor: 'pointer',
+						width: (100 / hourGridSize) + '%',
+						textAlign: 'center',
+						overflow: 'hidden'
+					});
+				});
+			}
+
+			if (o.showMinute && o.minuteGrid > 0) {
+				size = 100 * minuteGridSize * o.minuteGrid / (minMax - o.minuteMin);
+				$tp.find(".ui_tpicker_minute table").css({
+					width: size + "%",
+					marginLeft: (size / (-2 * minuteGridSize)) + "%",
+					borderCollapse: 'collapse'
+				}).find("td").each(function(index) {
+					$(this).click(function() {
+						tp_inst.minute_slider.slider("option", "value", $(this).html());
+						tp_inst._onTimeChange();
+						tp_inst._onSelectHandler();
+					}).css({
+						cursor: 'pointer',
+						width: (100 / minuteGridSize) + '%',
+						textAlign: 'center',
+						overflow: 'hidden'
+					});
+				});
+			}
+
+			if (o.showSecond && o.secondGrid > 0) {
+				$tp.find(".ui_tpicker_second table").css({
+					width: size + "%",
+					marginLeft: (size / (-2 * secondGridSize)) + "%",
+					borderCollapse: 'collapse'
+				}).find("td").each(function(index) {
+					$(this).click(function() {
+						tp_inst.second_slider.slider("option", "value", $(this).html());
+						tp_inst._onTimeChange();
+						tp_inst._onSelectHandler();
+					}).css({
+						cursor: 'pointer',
+						width: (100 / secondGridSize) + '%',
+						textAlign: 'center',
+						overflow: 'hidden'
+					});
+				});
+			}
+
+			if (o.showMillisec && o.millisecGrid > 0) {
+				$tp.find(".ui_tpicker_millisec table").css({
+					width: size + "%",
+					marginLeft: (size / (-2 * millisecGridSize)) + "%",
+					borderCollapse: 'collapse'
+				}).find("td").each(function(index) {
+					$(this).click(function() {
+						tp_inst.millisec_slider.slider("option", "value", $(this).html());
+						tp_inst._onTimeChange();
+						tp_inst._onSelectHandler();
+					}).css({
+						cursor: 'pointer',
+						width: (100 / millisecGridSize) + '%',
+						textAlign: 'center',
+						overflow: 'hidden'
+					});
+				});
+			}
+
+			var $buttonPanel = $dp.find('.ui-datepicker-buttonpane');
+			if ($buttonPanel.length) $buttonPanel.before($tp);
+			else $dp.append($tp);
+
+			this.$timeObj = $tp.find('#ui_tpicker_time_'+ dp_id);
+
+			if (this.inst !== null) {
+				var timeDefined = this.timeDefined;
+				this._onTimeChange();
+				this.timeDefined = timeDefined;
+			}
+
+			//Emulate datepicker onSelect behavior. Call on slidestop.
+			var onSelectDelegate = function() {
+				tp_inst._onSelectHandler();
+			};
+			this.hour_slider.bind('slidestop',onSelectDelegate);
+			this.minute_slider.bind('slidestop',onSelectDelegate);
+			this.second_slider.bind('slidestop',onSelectDelegate);
+			this.millisec_slider.bind('slidestop',onSelectDelegate);
+		}
+	},
+
+	//########################################################################
+	// This function tries to limit the ability to go outside the
+	// min/max date range
+	//########################################################################
+	_limitMinMaxDateTime: function(dp_inst, adjustSliders){
+		var o = this._defaults,
+			dp_date = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay);
+
+		if(!this._defaults.showTimepicker) return; // No time so nothing to check here
+
+		if($.datepicker._get(dp_inst, 'minDateTime') !== null && $.datepicker._get(dp_inst, 'minDateTime') !== undefined && dp_date){
+			var minDateTime = $.datepicker._get(dp_inst, 'minDateTime'),
+				minDateTimeDate = new Date(minDateTime.getFullYear(), minDateTime.getMonth(), minDateTime.getDate(), 0, 0, 0, 0);
+
+			if(this.hourMinOriginal === null || this.minuteMinOriginal === null || this.secondMinOriginal === null || this.millisecMinOriginal === null){
+				this.hourMinOriginal = o.hourMin;
+				this.minuteMinOriginal = o.minuteMin;
+				this.secondMinOriginal = o.secondMin;
+				this.millisecMinOriginal = o.millisecMin;
+			}
+
+			if(dp_inst.settings.timeOnly || minDateTimeDate.getTime() == dp_date.getTime()) {
+				this._defaults.hourMin = minDateTime.getHours();
+				if (this.hour <= this._defaults.hourMin) {
+					this.hour = this._defaults.hourMin;
+					this._defaults.minuteMin = minDateTime.getMinutes();
+					if (this.minute <= this._defaults.minuteMin) {
+						this.minute = this._defaults.minuteMin;
+						this._defaults.secondMin = minDateTime.getSeconds();
+					} else if (this.second <= this._defaults.secondMin){
+						this.second = this._defaults.secondMin;
+						this._defaults.millisecMin = minDateTime.getMilliseconds();
+					} else {
+						if(this.millisec < this._defaults.millisecMin)
+							this.millisec = this._defaults.millisecMin;
+						this._defaults.millisecMin = this.millisecMinOriginal;
+					}
+				} else {
+					this._defaults.minuteMin = this.minuteMinOriginal;
+					this._defaults.secondMin = this.secondMinOriginal;
+					this._defaults.millisecMin = this.millisecMinOriginal;
+				}
+			}else{
+				this._defaults.hourMin = this.hourMinOriginal;
+				this._defaults.minuteMin = this.minuteMinOriginal;
+				this._defaults.secondMin = this.secondMinOriginal;
+				this._defaults.millisecMin = this.millisecMinOriginal;
+			}
+		}
+
+		if($.datepicker._get(dp_inst, 'maxDateTime') !== null && $.datepicker._get(dp_inst, 'maxDateTime') !== undefined && dp_date){
+			var maxDateTime = $.datepicker._get(dp_inst, 'maxDateTime'),
+				maxDateTimeDate = new Date(maxDateTime.getFullYear(), maxDateTime.getMonth(), maxDateTime.getDate(), 0, 0, 0, 0);
+
+			if(this.hourMaxOriginal === null || this.minuteMaxOriginal === null || this.secondMaxOriginal === null){
+				this.hourMaxOriginal = o.hourMax;
+				this.minuteMaxOriginal = o.minuteMax;
+				this.secondMaxOriginal = o.secondMax;
+				this.millisecMaxOriginal = o.millisecMax;
+			}
+
+			if(dp_inst.settings.timeOnly || maxDateTimeDate.getTime() == dp_date.getTime()){
+				this._defaults.hourMax = maxDateTime.getHours();
+				if (this.hour >= this._defaults.hourMax) {
+					this.hour = this._defaults.hourMax;
+					this._defaults.minuteMax = maxDateTime.getMinutes();
+					if (this.minute >= this._defaults.minuteMax) {
+						this.minute = this._defaults.minuteMax;
+						this._defaults.secondMax = maxDateTime.getSeconds();
+					} else if (this.second >= this._defaults.secondMax) {
+						this.second = this._defaults.secondMax;
+						this._defaults.millisecMax = maxDateTime.getMilliseconds();
+					} else {
+						if(this.millisec > this._defaults.millisecMax) this.millisec = this._defaults.millisecMax;
+						this._defaults.millisecMax = this.millisecMaxOriginal;
+					}
+				} else {
+					this._defaults.minuteMax = this.minuteMaxOriginal;
+					this._defaults.secondMax = this.secondMaxOriginal;
+					this._defaults.millisecMax = this.millisecMaxOriginal;
+				}
+			}else{
+				this._defaults.hourMax = this.hourMaxOriginal;
+				this._defaults.minuteMax = this.minuteMaxOriginal;
+				this._defaults.secondMax = this.secondMaxOriginal;
+				this._defaults.millisecMax = this.millisecMaxOriginal;
+			}
+		}
+
+		if(adjustSliders !== undefined && adjustSliders === true){
+			var hourMax = (this._defaults.hourMax - ((this._defaults.hourMax - this._defaults.hourMin) % this._defaults.stepHour)).toFixed(0),
+                minMax  = (this._defaults.minuteMax - ((this._defaults.minuteMax - this._defaults.minuteMin) % this._defaults.stepMinute)).toFixed(0),
+                secMax  = (this._defaults.secondMax - ((this._defaults.secondMax - this._defaults.secondMin) % this._defaults.stepSecond)).toFixed(0),
+				millisecMax  = (this._defaults.millisecMax - ((this._defaults.millisecMax - this._defaults.millisecMin) % this._defaults.stepMillisec)).toFixed(0);
+
+			if(this.hour_slider)
+				this.hour_slider.slider("option", { min: this._defaults.hourMin, max: hourMax }).slider('value', this.hour);
+			if(this.minute_slider)
+				this.minute_slider.slider("option", { min: this._defaults.minuteMin, max: minMax }).slider('value', this.minute);
+			if(this.second_slider)
+				this.second_slider.slider("option", { min: this._defaults.secondMin, max: secMax }).slider('value', this.second);
+			if(this.millisec_slider)
+				this.millisec_slider.slider("option", { min: this._defaults.millisecMin, max: millisecMax }).slider('value', this.millisec);
+		}
+
+	},
+
+	
+	//########################################################################
+	// when a slider moves, set the internal time...
+	// on time change is also called when the time is updated in the text field
+	//########################################################################
+	_onTimeChange: function() {
+		var hour   = (this.hour_slider) ? this.hour_slider.slider('value') : false,
+			minute = (this.minute_slider) ? this.minute_slider.slider('value') : false,
+			second = (this.second_slider) ? this.second_slider.slider('value') : false,
+			millisec = (this.millisec_slider) ? this.millisec_slider.slider('value') : false,
+			timezone = (this.timezone_select) ? this.timezone_select.val() : false,
+			o = this._defaults;
+
+		if (typeof(hour) == 'object') hour = false;
+		if (typeof(minute) == 'object') minute = false;
+		if (typeof(second) == 'object') second = false;
+		if (typeof(millisec) == 'object') millisec = false;
+		if (typeof(timezone) == 'object') timezone = false;
+
+		if (hour !== false) hour = parseInt(hour,10);
+		if (minute !== false) minute = parseInt(minute,10);
+		if (second !== false) second = parseInt(second,10);
+		if (millisec !== false) millisec = parseInt(millisec,10);
+
+		var ampm = o[hour < 12 ? 'amNames' : 'pmNames'][0];
+
+		// If the update was done in the input field, the input field should not be updated.
+		// If the update was done using the sliders, update the input field.
+		var hasChanged = (hour != this.hour || minute != this.minute
+				|| second != this.second || millisec != this.millisec
+				|| (this.ampm.length > 0
+				    && (hour < 12) != ($.inArray(this.ampm.toUpperCase(), this.amNames) !== -1))
+				|| timezone != this.timezone);
+		
+		if (hasChanged) {
+
+			if (hour !== false)this.hour = hour;
+			if (minute !== false) this.minute = minute;
+			if (second !== false) this.second = second;
+			if (millisec !== false) this.millisec = millisec;
+			if (timezone !== false) this.timezone = timezone;
+			
+			if (!this.inst) this.inst = $.datepicker._getInst(this.$input[0]);
+			
+			this._limitMinMaxDateTime(this.inst, true);
+		}
+		if (o.ampm) this.ampm = ampm;
+		
+		this._formatTime();
+		if (this.$timeObj) this.$timeObj.text(this.formattedTime + o.timeSuffix);
+		this.timeDefined = true;
+		if (hasChanged) this._updateDateTime();
+	},
+    
+	//########################################################################
+	// call custom onSelect. 
+	// bind to sliders slidestop, and grid click.
+	//########################################################################
+	_onSelectHandler: function() {
+		var onSelect = this._defaults.onSelect;
+		var inputEl = this.$input ? this.$input[0] : null;
+		if (onSelect && inputEl) {
+			onSelect.apply(inputEl, [this.formattedDateTime, this]);
+		}
+	},
+
+	//########################################################################
+	// format the time all pretty...
+	//########################################################################
+	_formatTime: function(time, format, ampm) {
+		if (ampm == undefined) ampm = this._defaults.ampm;
+		time = time || { hour: this.hour, minute: this.minute, second: this.second, millisec: this.millisec, ampm: this.ampm, timezone: this.timezone };
+		var tmptime = (format || this._defaults.timeFormat).toString();
+
+		var hour = parseInt(time.hour, 10);
+		if (ampm) {
+			if (!$.inArray(time.ampm.toUpperCase(), this.amNames) !== -1)
+				hour = hour % 12;
+			if (hour === 0)
+				hour = 12;
+		}
+		tmptime = tmptime.replace(/(?:hh?|mm?|ss?|[tT]{1,2}|[lz])/g, function(match) {
+			switch (match.toLowerCase()) {
+				case 'hh': return ('0' + hour).slice(-2);
+				case 'h':  return hour;
+				case 'mm': return ('0' + time.minute).slice(-2);
+				case 'm':  return time.minute;
+				case 'ss': return ('0' + time.second).slice(-2);
+				case 's':  return time.second;
+				case 'l':  return ('00' + time.millisec).slice(-3);
+				case 'z':  return time.timezone;
+				case 't': case 'tt':
+					if (ampm) {
+						var _ampm = time.ampm;
+						if (match.length == 1)
+							_ampm = _ampm.charAt(0);
+						return match.charAt(0) == 'T' ? _ampm.toUpperCase() : _ampm.toLowerCase();
+					}
+					return '';
+			}
+		});
+
+		if (arguments.length) return tmptime;
+		else this.formattedTime = tmptime;
+	},
+
+	//########################################################################
+	// update our input with the new date time..
+	//########################################################################
+	_updateDateTime: function(dp_inst) {
+		dp_inst = this.inst || dp_inst,
+			dt = new Date(dp_inst.selectedYear, dp_inst.selectedMonth, dp_inst.selectedDay),
+			dateFmt = $.datepicker._get(dp_inst, 'dateFormat'),
+			formatCfg = $.datepicker._getFormatConfig(dp_inst),
+			timeAvailable = dt !== null && this.timeDefined;
+		this.formattedDate = $.datepicker.formatDate(dateFmt, (dt === null ? new Date() : dt), formatCfg);
+		var formattedDateTime = this.formattedDate;
+		if (dp_inst.lastVal !== undefined && (dp_inst.lastVal.length > 0 && this.$input.val().length === 0))
+			return;
+
+		if (this._defaults.timeOnly === true) {
+			formattedDateTime = this.formattedTime;
+		} else if (this._defaults.timeOnly !== true && (this._defaults.alwaysSetTime || timeAvailable)) {
+			formattedDateTime += this._defaults.separator + this.formattedTime + this._defaults.timeSuffix;
+		}
+
+		this.formattedDateTime = formattedDateTime;
+
+		if(!this._defaults.showTimepicker) {
+			this.$input.val(this.formattedDate);
+		} else if (this.$altInput && this._defaults.altFieldTimeOnly === true) {
+			this.$altInput.val(this.formattedTime);
+			this.$input.val(this.formattedDate);
+		} else if(this.$altInput) {
+			this.$altInput.val(formattedDateTime);
+			this.$input.val(formattedDateTime);
+		} else {
+			this.$input.val(formattedDateTime);
+		}
+		
+		this.$input.trigger("change");
+	}
+
+});
+
+$.fn.extend({
+	//########################################################################
+	// shorthand just to use timepicker..
+	//########################################################################
+	timepicker: function(o) {
+		o = o || {};
+		var tmp_args = arguments;
+
+		if (typeof o == 'object') tmp_args[0] = $.extend(o, { timeOnly: true });
+
+		return $(this).each(function() {
+			$.fn.datetimepicker.apply($(this), tmp_args);
+		});
+	},
+
+	//########################################################################
+	// extend timepicker to datepicker
+	//########################################################################
+	datetimepicker: function(o) {
+		o = o || {};
+		var $input = this,
+		tmp_args = arguments;
+
+		if (typeof(o) == 'string'){
+			if(o == 'getDate') 
+				return $.fn.datepicker.apply($(this[0]), tmp_args);
+			else 
+				return this.each(function() {
+					var $t = $(this);
+					$t.datepicker.apply($t, tmp_args);
+				});
+		}
+		else
+			return this.each(function() {
+				var $t = $(this);
+				$t.datepicker($.timepicker._newInst($t, o)._defaults);
+			});
+	}
+});
+
+//########################################################################
+// the bad hack :/ override datepicker so it doesnt close on select
+// inspired: http://stackoverflow.com/questions/1252512/jquery-datepicker-prevent-closing-picker-when-clicking-a-date/1762378#1762378
+//########################################################################
+$.datepicker._base_selectDate = $.datepicker._selectDate;
+$.datepicker._selectDate = function (id, dateStr) {
+	var inst = this._getInst($(id)[0]),
+		tp_inst = this._get(inst, 'timepicker');
+
+	if (tp_inst) {
+		tp_inst._limitMinMaxDateTime(inst, true);
+		inst.inline = inst.stay_open = true;
+		//This way the onSelect handler called from calendarpicker get the full dateTime
+		this._base_selectDate(id, dateStr);
+		inst.inline = inst.stay_open = false;
+		this._notifyChange(inst);
+		this._updateDatepicker(inst);
+	}
+	else this._base_selectDate(id, dateStr);
+};
+
+//#############################################################################################
+// second bad hack :/ override datepicker so it triggers an event when changing the input field
+// and does not redraw the datepicker on every selectDate event
+//#############################################################################################
+$.datepicker._base_updateDatepicker = $.datepicker._updateDatepicker;
+$.datepicker._updateDatepicker = function(inst) {
+
+	// don't popup the datepicker if there is another instance already opened
+	var input = inst.input[0];
+	if($.datepicker._curInst &&
+	   $.datepicker._curInst != inst &&
+	   $.datepicker._datepickerShowing &&
+	   $.datepicker._lastInput != input) {
+		return;
+	}
+
+	if (typeof(inst.stay_open) !== 'boolean' || inst.stay_open === false) {
+		this._base_updateDatepicker(inst);
+		
+		// Reload the time control when changing something in the input text field.
+		var tp_inst = this._get(inst, 'timepicker');
+		if(tp_inst) tp_inst._addTimePicker(inst);
+	}
+};
+
+//#######################################################################################
+// third bad hack :/ override datepicker so it allows spaces and colon in the input field
+//#######################################################################################
+$.datepicker._base_doKeyPress = $.datepicker._doKeyPress;
+$.datepicker._doKeyPress = function(event) {
+	var inst = $.datepicker._getInst(event.target),
+		tp_inst = $.datepicker._get(inst, 'timepicker');
+
+	if (tp_inst) {
+		if ($.datepicker._get(inst, 'constrainInput')) {
+			var ampm = tp_inst._defaults.ampm,
+				dateChars = $.datepicker._possibleChars($.datepicker._get(inst, 'dateFormat')),
+				datetimeChars = tp_inst._defaults.timeFormat.toString()
+								.replace(/[hms]/g, '')
+								.replace(/TT/g, ampm ? 'APM' : '')
+								.replace(/Tt/g, ampm ? 'AaPpMm' : '')
+								.replace(/tT/g, ampm ? 'AaPpMm' : '')
+								.replace(/T/g, ampm ? 'AP' : '')
+								.replace(/tt/g, ampm ? 'apm' : '')
+								.replace(/t/g, ampm ? 'ap' : '') +
+								" " +
+								tp_inst._defaults.separator +
+								tp_inst._defaults.timeSuffix +
+								(tp_inst._defaults.showTimezone ? tp_inst._defaults.timezoneList.join('') : '') +
+								(tp_inst._defaults.amNames.join('')) +
+								(tp_inst._defaults.pmNames.join('')) +
+								dateChars,
+				chr = String.fromCharCode(event.charCode === undefined ? event.keyCode : event.charCode);
+			return event.ctrlKey || (chr < ' ' || !dateChars || datetimeChars.indexOf(chr) > -1);
+		}
+	}
+	
+	return $.datepicker._base_doKeyPress(event);
+};
+
+//#######################################################################################
+// Override key up event to sync manual input changes.
+//#######################################################################################
+$.datepicker._base_doKeyUp = $.datepicker._doKeyUp;
+$.datepicker._doKeyUp = function (event) {
+	var inst = $.datepicker._getInst(event.target),
+		tp_inst = $.datepicker._get(inst, 'timepicker');
+
+	if (tp_inst) {
+		if (tp_inst._defaults.timeOnly && (inst.input.val() != inst.lastVal)) {
+			try {
+				$.datepicker._updateDatepicker(inst);
+			}
+			catch (err) {
+				$.datepicker.log(err);
+			}
+		}
+	}
+
+	return $.datepicker._base_doKeyUp(event);
+};
+
+//#######################################################################################
+// override "Today" button to also grab the time.
+//#######################################################################################
+$.datepicker._base_gotoToday = $.datepicker._gotoToday;
+$.datepicker._gotoToday = function(id) {
+	var inst = this._getInst($(id)[0]),
+		$dp = inst.dpDiv;
+	this._base_gotoToday(id);
+	var now = new Date();
+	var tp_inst = this._get(inst, 'timepicker');
+	if (tp_inst._defaults.showTimezone && tp_inst.timezone_select) {
+		var tzoffset = now.getTimezoneOffset(); // If +0100, returns -60
+		var tzsign = tzoffset > 0 ? '-' : '+';
+		tzoffset = Math.abs(tzoffset);
+		var tzmin = tzoffset % 60
+		tzoffset = tzsign + ('0' + (tzoffset - tzmin) / 60).slice(-2) + ('0' + tzmin).slice(-2);
+		if (tp_inst._defaults.timezoneIso8609)
+			tzoffset = tzoffset.substring(0, 3) + ':' + tzoffset.substring(3);
+		tp_inst.timezone_select.val(tzoffset);
+	}
+	this._setTime(inst, now);
+	$( '.ui-datepicker-today', $dp).click(); 
+};
+
+//#######################################################################################
+// Disable & enable the Time in the datetimepicker
+//#######################################################################################
+$.datepicker._disableTimepickerDatepicker = function(target, date, withDate) {
+	var inst = this._getInst(target),
+	tp_inst = this._get(inst, 'timepicker');
+	$(target).datepicker('getDate'); // Init selected[Year|Month|Day]
+	if (tp_inst) {
+		tp_inst._defaults.showTimepicker = false;
+		tp_inst._updateDateTime(inst);
+	}
+};
+
+$.datepicker._enableTimepickerDatepicker = function(target, date, withDate) {
+	var inst = this._getInst(target),
+	tp_inst = this._get(inst, 'timepicker');
+	$(target).datepicker('getDate'); // Init selected[Year|Month|Day]
+	if (tp_inst) {
+		tp_inst._defaults.showTimepicker = true;
+		tp_inst._addTimePicker(inst); // Could be disabled on page load
+		tp_inst._updateDateTime(inst);
+	}
+};
+
+//#######################################################################################
+// Create our own set time function
+//#######################################################################################
+$.datepicker._setTime = function(inst, date) {
+	var tp_inst = this._get(inst, 'timepicker');
+	if (tp_inst) {
+		var defaults = tp_inst._defaults,
+			// calling _setTime with no date sets time to defaults
+			hour = date ? date.getHours() : defaults.hour,
+			minute = date ? date.getMinutes() : defaults.minute,
+			second = date ? date.getSeconds() : defaults.second,
+			millisec = date ? date.getMilliseconds() : defaults.millisec;
+
+		//check if within min/max times..
+		if ((hour < defaults.hourMin || hour > defaults.hourMax) || (minute < defaults.minuteMin || minute > defaults.minuteMax) || (second < defaults.secondMin || second > defaults.secondMax) || (millisec < defaults.millisecMin || millisec > defaults.millisecMax)) {
+			hour = defaults.hourMin;
+			minute = defaults.minuteMin;
+			second = defaults.secondMin;
+			millisec = defaults.millisecMin;
+		}
+
+		tp_inst.hour = hour;
+		tp_inst.minute = minute;
+		tp_inst.second = second;
+		tp_inst.millisec = millisec;
+
+		if (tp_inst.hour_slider) tp_inst.hour_slider.slider('value', hour);
+		if (tp_inst.minute_slider) tp_inst.minute_slider.slider('value', minute);
+		if (tp_inst.second_slider) tp_inst.second_slider.slider('value', second);
+		if (tp_inst.millisec_slider) tp_inst.millisec_slider.slider('value', millisec);
+
+		tp_inst._onTimeChange();
+		tp_inst._updateDateTime(inst);
+	}
+};
+
+//#######################################################################################
+// Create new public method to set only time, callable as $().datepicker('setTime', date)
+//#######################################################################################
+$.datepicker._setTimeDatepicker = function(target, date, withDate) {
+	var inst = this._getInst(target),
+		tp_inst = this._get(inst, 'timepicker');
+
+	if (tp_inst) {
+		this._setDateFromField(inst);
+		var tp_date;
+		if (date) {
+			if (typeof date == "string") {
+				tp_inst._parseTime(date, withDate);
+				tp_date = new Date();
+				tp_date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
+			}
+			else tp_date = new Date(date.getTime());
+			if (tp_date.toString() == 'Invalid Date') tp_date = undefined;
+			this._setTime(inst, tp_date);
+		}
+	}
+
+};
+
+//#######################################################################################
+// override setDate() to allow setting time too within Date object
+//#######################################################################################
+$.datepicker._base_setDateDatepicker = $.datepicker._setDateDatepicker;
+$.datepicker._setDateDatepicker = function(target, date) {
+	var inst = this._getInst(target),
+	tp_date = (date instanceof Date) ? new Date(date.getTime()) : date;
+
+	this._updateDatepicker(inst);
+	this._base_setDateDatepicker.apply(this, arguments);
+	this._setTimeDatepicker(target, tp_date, true);
+};
+
+//#######################################################################################
+// override getDate() to allow getting time too within Date object
+//#######################################################################################
+$.datepicker._base_getDateDatepicker = $.datepicker._getDateDatepicker;
+$.datepicker._getDateDatepicker = function(target, noDefault) {
+	var inst = this._getInst(target),
+		tp_inst = this._get(inst, 'timepicker');
+
+	if (tp_inst) {
+		this._setDateFromField(inst, noDefault);
+		var date = this._getDate(inst);
+		if (date && tp_inst._parseTime($(target).val(), tp_inst.timeOnly)) date.setHours(tp_inst.hour, tp_inst.minute, tp_inst.second, tp_inst.millisec);
+		return date;
+	}
+	return this._base_getDateDatepicker(target, noDefault);
+};
+
+//#######################################################################################
+// override parseDate() because UI 1.8.14 throws an error about "Extra characters"
+// An option in datapicker to ignore extra format characters would be nicer.
+//#######################################################################################
+$.datepicker._base_parseDate = $.datepicker.parseDate;
+$.datepicker.parseDate = function(format, value, settings) {
+	var date;
+	try {
+		date = this._base_parseDate(format, value, settings);
+	} catch (err) {
+		// Hack!  The error message ends with a colon, a space, and
+		// the "extra" characters.  We rely on that instead of
+		// attempting to perfectly reproduce the parsing algorithm.
+		date = this._base_parseDate(format, value.substring(0,value.length-(err.length-err.indexOf(':')-2)), settings);
+	}
+	return date;
+};
+
+//#######################################################################################
+// override formatDate to set date with time to the input
+//#######################################################################################
+$.datepicker._base_formatDate=$.datepicker._formatDate;
+$.datepicker._formatDate = function(inst, day, month, year){
+	var tp_inst = this._get(inst, 'timepicker');
+	if(tp_inst)
+	{
+		if(day)
+			var b = this._base_formatDate(inst, day, month, year);
+		tp_inst._updateDateTime();	
+		return tp_inst.$input.val();
+	}
+	return this._base_formatDate(inst);
+}
+
+//#######################################################################################
+// override options setter to add time to maxDate(Time) and minDate(Time). MaxDate
+//#######################################################################################
+$.datepicker._base_optionDatepicker = $.datepicker._optionDatepicker;
+$.datepicker._optionDatepicker = function(target, name, value) {
+	var inst = this._getInst(target),
+		tp_inst = this._get(inst, 'timepicker');
+	if (tp_inst) {
+		var min,max,onselect;
+		if (typeof name == 'string') { // if min/max was set with the string
+			if (name==='minDate' || name==='minDateTime' )
+				min = value;
+			else if (name==='maxDate' || name==='maxDateTime')
+				max = value;
+			else if (name==='onSelect')
+				onselect=value;
+		} else if (typeof name == 'object') { //if min/max was set with the JSON
+			if(name.minDate)
+				min = name.minDate;
+			else if (name.minDateTime)
+				min = name.minDateTime;
+			else if (name.maxDate)
+				max = name.maxDate;
+			else if (name.maxDateTime)
+				max = name.maxDateTime;
+		}
+		if(min){ //if min was set
+			if(min==0)
+				min=new Date();
+			else
+				min= new Date(min);
+			
+			tp_inst._defaults.minDate = min;
+			tp_inst._defaults.minDateTime = min;
+		} else if (max){ //if max was set
+			if(max==0)
+				max=new Date();
+			else
+				max= new Date(max);
+			tp_inst._defaults.maxDate = max;
+			tp_inst._defaults.maxDateTime = max;
+		}
+		else if (onselect)
+			tp_inst._defaults.onSelect=onselect;
+	}
+	this._base_optionDatepicker(target, name, value);
+};
+
+//#######################################################################################
+// jQuery extend now ignores nulls!
+//#######################################################################################
+function extendRemove(target, props) {
+	$.extend(target, props);
+	for (var name in props)
+		if (props[name] === null || props[name] === undefined)
+			target[name] = props[name];
+	return target;
+}
+
+$.timepicker = new Timepicker(); // singleton instance
+$.timepicker.version = "0.9.7";
+
+})(jQuery);
+
diff --git a/share/html/NoAuth/js/ui.timepickr.js b/share/html/NoAuth/js/ui.timepickr.js
deleted file mode 100644
index 3b2040a..0000000
--- a/share/html/NoAuth/js/ui.timepickr.js
+++ /dev/null
@@ -1,941 +0,0 @@
-/*
-  jQuery utils - @VERSION
-  http://code.google.com/p/jquery-utils/
-
-  (c) Maxime Haineault <haineault at gmail.com> 
-  http://haineault.com
-
-  MIT License (http://www.opensource.org/licenses/mit-license.php
-
-*/
-
-(function($){
-     $.extend($.expr[':'], {
-        // case insensitive version of :contains
-        icontains: function(a,i,m){return (a.textContent||a.innerText||jQuery(a).text()||"").toLowerCase().indexOf(m[3].toLowerCase())>=0;}
-    });
-
-    $.iterators = {
-        getText:  function() { return $(this).text(); },
-        parseInt: function(v){ return parseInt(v, 10); }
-    };
-
-	$.extend({ 
-
-        // Returns a range object
-        // Author: Matthias Miller
-        // Site:   http://blog.outofhanwell.com/2006/03/29/javascript-range-function/
-        range:  function() {
-            if (!arguments.length) { return []; }
-            var min, max, step;
-            if (arguments.length == 1) {
-                min  = 0;
-                max  = arguments[0]-1;
-                step = 1;
-            }
-            else {
-                // default step to 1 if it's zero or undefined
-                min  = arguments[0];
-                max  = arguments[1]-1;
-                step = arguments[2] || 1;
-            }
-            // convert negative steps to positive and reverse min/max
-            if (step < 0 && min >= max) {
-                step *= -1;
-                var tmp = min;
-                min = max;
-                max = tmp;
-                min += ((max-min) % step);
-            }
-            var a = [];
-            for (var i = min; i <= max; i += step) { a.push(i); }
-            return a;
-        },
-
-        // Taken from ui.core.js. 
-        // Why are you keeping this gem for yourself guys ? :|
-        keyCode: {
-            BACKSPACE: 8, CAPS_LOCK: 20, COMMA: 188, CONTROL: 17, DELETE: 46, DOWN: 40,
-            END: 35, ENTER: 13, ESCAPE: 27, HOME: 36, INSERT:  45, LEFT: 37,
-            NUMPAD_ADD: 107, NUMPAD_DECIMAL: 110, NUMPAD_DIVIDE: 111, NUMPAD_ENTER: 108, 
-            NUMPAD_MULTIPLY: 106, NUMPAD_SUBTRACT: 109, PAGE_DOWN: 34, PAGE_UP: 33, 
-            PERIOD: 190, RIGHT: 39, SHIFT: 16, SPACE: 32, TAB: 9, UP: 38
-        },
-        
-        // Takes a keyboard event and return true if the keycode match the specified keycode
-        keyIs: function(k, e) {
-            return parseInt($.keyCode[k.toUpperCase()], 10) == parseInt((typeof(e) == 'number' )? e: e.keyCode, 10);
-        },
-        
-        // Returns the key of an array
-        keys: function(arr) {
-            var o = [];
-            for (k in arr) { o.push(k); }
-            return o;
-        },
-
-        // Redirect to a specified url
-        redirect: function(url) {
-            window.location.href = url;
-            return url;
-        },
-
-        // Stop event shorthand
-        stop: function(e, preventDefault, stopPropagation) {
-            if (preventDefault)  { e.preventDefault(); }
-            if (stopPropagation) { e.stopPropagation(); }
-            return preventDefault && false || true;
-        },
-
-        // Returns the basename of a path
-        basename: function(path) {
-            var t = path.split('/');
-            return t[t.length] === '' && s || t.slice(0, t.length).join('/');
-        },
-
-        // Returns the filename of a path
-        filename: function(path) {
-            return path.split('/').pop();
-        }, 
-
-        // Returns a formated file size
-        filesizeformat: function(bytes, suffixes){
-            var b = parseInt(bytes, 10);
-            var s = suffixes || ['byte', 'bytes', 'KB', 'MB', 'GB'];
-            if (isNaN(b) || b === 0) { return '0 ' + s[0]; }
-            if (b == 1)              { return '1 ' + s[0]; }
-            if (b < 1024)            { return  b.toFixed(2) + ' ' + s[1]; }
-            if (b < 1048576)         { return (b / 1024).toFixed(2) + ' ' + s[2]; }
-            if (b < 1073741824)      { return (b / 1048576).toFixed(2) + ' '+ s[3]; }
-            else                     { return (b / 1073741824).toFixed(2) + ' '+ s[4]; }
-        },
-
-        fileExtension: function(s) {
-            var tokens = s.split('.');
-            return tokens[tokens.length-1] || false;
-        },
-        
-        // Returns true if an object is a String
-        isString: function(o) {
-            return typeof(o) == 'string' && true || false;
-        },
-        
-        // Returns true if an object is a RegExp
-		isRegExp: function(o) {
-			return o && o.constructor.toString().indexOf('RegExp()') != -1 || false;
-		},
-
-        isObject: function(o) {
-            return (typeof(o) == 'object');
-        },
-        
-        // Convert input to currency (two decimal fixed number)
-		toCurrency: function(i) {
-			i = parseFloat(i, 10).toFixed(2);
-			return (i=='NaN') ? '0.00' : i;
-		},
-
-        /*-------------------------------------------------------------------- 
-         * javascript method: "pxToEm"
-         * by:
-           Scott Jehl (scott at filamentgroup.com) 
-           Maggie Wachs (maggie at filamentgroup.com)
-           http://www.filamentgroup.com
-         *
-         * Copyright (c) 2008 Filament Group
-         * Dual licensed under the MIT (filamentgroup.com/examples/mit-license.txt) and GPL (filamentgroup.com/examples/gpl-license.txt) licenses.
-         *
-         * Description: pxToEm converts a pixel value to ems depending on inherited font size.  
-         * Article: http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/
-         * Demo: http://www.filamentgroup.com/examples/pxToEm/	 	
-         *							
-         * Options:  	 								
-                scope: string or jQuery selector for font-size scoping
-                reverse: Boolean, true reverses the conversion to em-px
-         * Dependencies: jQuery library						  
-         * Usage Example: myPixelValue.pxToEm(); or myPixelValue.pxToEm({'scope':'#navigation', reverse: true});
-         *
-         * Version: 2.1, 18.12.2008
-         * Changelog:
-         *		08.02.2007 initial Version 1.0
-         *		08.01.2008 - fixed font-size calculation for IE
-         *		18.12.2008 - removed native object prototyping to stay in jQuery's spirit, jsLinted (Maxime Haineault <haineault at gmail.com>)
-        --------------------------------------------------------------------*/
-
-        pxToEm: function(i, settings){
-            //set defaults
-            settings = jQuery.extend({
-                scope: 'body',
-                reverse: false
-            }, settings);
-            
-            var pxVal = (i === '') ? 0 : parseFloat(i);
-            var scopeVal;
-            var getWindowWidth = function(){
-                var de = document.documentElement;
-                return self.innerWidth || (de && de.clientWidth) || document.body.clientWidth;
-            };	
-            
-            /* When a percentage-based font-size is set on the body, IE returns that percent of the window width as the font-size. 
-                For example, if the body font-size is 62.5% and the window width is 1000px, IE will return 625px as the font-size. 	
-                When this happens, we calculate the correct body font-size (%) and multiply it by 16 (the standard browser font size) 
-                to get an accurate em value. */
-                        
-            if (settings.scope == 'body' && $.browser.msie && (parseFloat($('body').css('font-size')) / getWindowWidth()).toFixed(1) > 0.0) {
-                var calcFontSize = function(){		
-                    return (parseFloat($('body').css('font-size'))/getWindowWidth()).toFixed(3) * 16;
-                };
-                scopeVal = calcFontSize();
-            }
-            else { scopeVal = parseFloat(jQuery(settings.scope).css("font-size")); }
-                    
-            var result = (settings.reverse === true) ? (pxVal * scopeVal).toFixed(2) + 'px' : (pxVal / scopeVal).toFixed(2) + 'em';
-            return result;
-        }
-	});
-
-	$.extend($.fn, { 
-        type: function() {
-            try { return $(this).get(0).nodeName.toLowerCase(); }
-            catch(e) { return false; }
-        },
-        // Select a text range in a textarea
-        selectRange: function(start, end){
-            // use only the first one since only one input can be focused
-            if ($(this).get(0).createTextRange) {
-                var range = $(this).get(0).createTextRange();
-                range.collapse(true);
-                range.moveEnd('character',   end);
-                range.moveStart('character', start);
-                range.select();
-            }
-            else if ($(this).get(0).setSelectionRange) {
-                $(this).bind('focus', function(e){
-                    e.preventDefault();
-                }).get(0).setSelectionRange(start, end);
-            }
-            return $(this);
-        },
-
-        /*-------------------------------------------------------------------- 
-         * JQuery Plugin: "EqualHeights"
-         * by:	Scott Jehl, Todd Parker, Maggie Costello Wachs (http://www.filamentgroup.com)
-         *
-         * Copyright (c) 2008 Filament Group
-         * Licensed under GPL (http://www.opensource.org/licenses/gpl-license.php)
-         *
-         * Description: Compares the heights or widths of the top-level children of a provided element 
-                and sets their min-height to the tallest height (or width to widest width). Sets in em units 
-                by default if pxToEm() method is available.
-         * Dependencies: jQuery library, pxToEm method	(article: 
-                http://www.filamentgroup.com/lab/retaining_scalable_interfaces_with_pixel_to_em_conversion/)							  
-         * Usage Example: $(element).equalHeights();
-                Optional: to set min-height in px, pass a true argument: $(element).equalHeights(true);
-         * Version: 2.1, 18.12.2008
-         *
-         * Note: Changed pxToEm call to call $.pxToEm instead, jsLinted (Maxime Haineault <haineault at gmail.com>)
-        --------------------------------------------------------------------*/
-
-        equalHeights: function(px){
-            $(this).each(function(){
-                var currentTallest = 0;
-                $(this).children().each(function(i){
-                    if ($(this).height() > currentTallest) { currentTallest = $(this).height(); }
-                });
-                if (!px || !$.pxToEm) { currentTallest = $.pxToEm(currentTallest); } //use ems unless px is specified
-                // for ie6, set height since min-height isn't supported
-                if ($.browser.msie && $.browser.version == 6.0) { $(this).children().css({'height': currentTallest}); }
-                $(this).children().css({'min-height': currentTallest}); 
-            });
-            return this;
-        },
-
-        // Copyright (c) 2009 James Padolsey
-        // http://james.padolsey.com/javascript/jquery-delay-plugin/
-        delay: function(time, callback){
-            jQuery.fx.step.delay = function(){};
-            return this.animate({delay:1}, time, callback);
-        }        
-	});
-})(jQuery);
-
-/*
-  jQuery strings - 0.4
-  http://code.google.com/p/jquery-utils/
-  
-  (c) Maxime Haineault <haineault at gmail.com>
-  http://haineault.com   
-
-  MIT License (http://www.opensource.org/licenses/mit-license.php)
-
-  Implementation of Python3K advanced string formatting
-  http://www.python.org/dev/peps/pep-3101/
-
-  Documentation: http://code.google.com/p/jquery-utils/wiki/StringFormat
-  
-*/
-(function($){
-    var strings = {
-        strConversion: {
-            // tries to translate any objects type into string gracefully
-            __repr: function(i){
-                switch(this.__getType(i)) {
-                    case 'array':case 'date':case 'number':
-                        return i.toString();
-                    case 'object': // Thanks to Richard Paul Lewis for the fix
-                        var o = []; 
-                        var l = i.length;
-                        for(var x=0;x<l;x++) {
-                          o.push(x+': '+this.__repr(i[x]));
-                        } 
-                        return o.join(', ');                        
-                    case 'string': 
-                        return i;
-                    default: 
-                        return i;
-                }
-            },
-            // like typeof but less vague
-            __getType: function(i) {
-                if (!i || !i.constructor) { return typeof(i); }
-                var match = i.constructor.toString().match(/Array|Number|String|Object|Date/);
-                return match && match[0].toLowerCase() || typeof(i);
-            },
-            // Jonas Raoni Soares Silva (http://jsfromhell.com/string/pad)
-            __pad: function(str, l, s, t){
-                var p = s || ' ';
-                var o = str;
-                if (l - str.length > 0) {
-                    o = new Array(Math.ceil(l / p.length)).join(p).substr(0, t = !t ? l : t == 1 ? 0 : Math.ceil(l / 2)) + str + p.substr(0, l - t);
-                }
-                return o;
-            },
-            __getInput: function(arg, args) {
-                 var key = arg.getKey();
-                switch(this.__getType(args)){
-                    case 'object': // Thanks to Jonathan Works for the patch
-                        var keys = key.split('.');
-                        var obj = args;
-                        for(var subkey = 0; subkey < keys.length; subkey++){
-                            obj = obj[keys[subkey]];
-                        }
-                        if (typeof(obj) != 'undefined') {
-                            if (strings.strConversion.__getType(obj) == 'array') {
-                                return arg.getFormat().match(/\.\*/) && obj[1] || obj;
-                            }
-                            return obj;
-                        }
-                        else {
-                            // TODO: try by numerical index                    
-                        }
-                    break;
-                    case 'array': 
-                        key = parseInt(key, 10);
-                        if (arg.getFormat().match(/\.\*/) && typeof args[key+1] != 'undefined') { return args[key+1]; }
-                        else if (typeof args[key] != 'undefined') { return args[key]; }
-                        else { return key; }
-                    break;
-                }
-                return '{'+key+'}';
-            },
-            __formatToken: function(token, args) {
-                var arg   = new Argument(token, args);
-                return strings.strConversion[arg.getFormat().slice(-1)](this.__getInput(arg, args), arg);
-            },
-
-            // Signed integer decimal.
-            d: function(input, arg){
-                var o = parseInt(input, 10); // enforce base 10
-                var p = arg.getPaddingLength();
-                if (p) { return this.__pad(o.toString(), p, arg.getPaddingString(), 0); }
-                else   { return o; }
-            },
-            // Signed integer decimal.
-            i: function(input, args){ 
-                return this.d(input, args);
-            },
-            // Unsigned octal
-            o: function(input, arg){ 
-                var o = input.toString(8);
-                if (arg.isAlternate()) { o = this.__pad(o, o.length+1, '0', 0); }
-                return this.__pad(o, arg.getPaddingLength(), arg.getPaddingString(), 0);
-            },
-            // Unsigned decimal
-            u: function(input, args) {
-                return Math.abs(this.d(input, args));
-            },
-            // Unsigned hexadecimal (lowercase)
-            x: function(input, arg){
-                var o = parseInt(input, 10).toString(16);
-                o = this.__pad(o, arg.getPaddingLength(), arg.getPaddingString(),0);
-                return arg.isAlternate() ? '0x'+o : o;
-            },
-            // Unsigned hexadecimal (uppercase)
-            X: function(input, arg){
-                return this.x(input, arg).toUpperCase();
-            },
-            // Floating point exponential format (lowercase)
-            e: function(input, arg){
-                return parseFloat(input, 10).toExponential(arg.getPrecision());
-            },
-            // Floating point exponential format (uppercase)
-            E: function(input, arg){
-                return this.e(input, arg).toUpperCase();
-            },
-            // Floating point decimal format
-            f: function(input, arg){
-                return this.__pad(parseFloat(input, 10).toFixed(arg.getPrecision()), arg.getPaddingLength(), arg.getPaddingString(),0);
-            },
-            // Floating point decimal format (alias)
-            F: function(input, args){
-                return this.f(input, args);
-            },
-            // Floating point format. Uses exponential format if exponent is greater than -4 or less than precision, decimal format otherwise
-            g: function(input, arg){
-                var o = parseFloat(input, 10);
-                return (o.toString().length > 6) ? Math.round(o.toExponential(arg.getPrecision())): o;
-            },
-            // Floating point format. Uses exponential format if exponent is greater than -4 or less than precision, decimal format otherwise
-            G: function(input, args){
-                return this.g(input, args);
-            },
-            // Single character (accepts integer or single character string). 	
-            c: function(input, args) {
-                var match = input.match(/\w|\d/);
-                return match && match[0] || '';
-            },
-            // String (converts any JavaScript object to anotated format)
-            r: function(input, args) {
-                return this.__repr(input);
-            },
-            // String (converts any JavaScript object using object.toString())
-            s: function(input, args) {
-                return input.toString && input.toString() || ''+input;
-            }
-        },
-
-        format: function(str, args) {
-            var end    = 0;
-            var start  = 0;
-            var match  = false;
-            var buffer = [];
-            var token  = '';
-            var tmp    = (str||'').split('');
-            for(start=0; start < tmp.length; start++) {
-                if (tmp[start] == '{' && tmp[start+1] !='{') {
-                    end   = str.indexOf('}', start);
-                    token = tmp.slice(start+1, end).join('');
-                    if (tmp[start-1] != '{' && tmp[end+1] != '}') {
-                        var tokenArgs = (typeof arguments[1] != 'object')? arguments2Array(arguments, 2): args || [];
-                        buffer.push(strings.strConversion.__formatToken(token, tokenArgs));
-                    }
-                    else {
-                        buffer.push(token);
-                    }
-                }
-                else if (start > end || buffer.length < 1) { buffer.push(tmp[start]); }
-            }
-            return (buffer.length > 1)? buffer.join(''): buffer[0];
-        },
-
-        calc: function(str, args) {
-            return eval(format(str, args));
-        },
-
-        repeat: function(s, n) { 
-            return new Array(n+1).join(s); 
-        },
-
-        UTF8encode: function(s) { 
-            return unescape(encodeURIComponent(s)); 
-        },
-
-        UTF8decode: function(s) { 
-            return decodeURIComponent(escape(s)); 
-        },
-
-        tpl: function() {
-            var out = '';
-            var render = true;
-            // Set
-            // $.tpl('ui.test', ['<span>', helloWorld ,'</span>']);
-            if (arguments.length == 2 && $.isArray(arguments[1])) {
-                this[arguments[0]] = arguments[1].join('');
-                return $(this[arguments[0]]);
-            }
-            // $.tpl('ui.test', '<span>hello world</span>');
-            if (arguments.length == 2 && $.isString(arguments[1])) {
-                this[arguments[0]] = arguments[1];
-                return $(this[arguments[0]]);
-            }
-            // Call
-            // $.tpl('ui.test');
-            if (arguments.length == 1) {
-                return $(this[arguments[0]]);
-            }
-            // $.tpl('ui.test', false);
-            if (arguments.length == 2 && arguments[1] == false) {
-                return this[arguments[0]];
-            }
-            // $.tpl('ui.test', {value:blah});
-            if (arguments.length == 2 && $.isObject(arguments[1])) {
-                return $($.format(this[arguments[0]], arguments[1]));
-            }
-            // $.tpl('ui.test', {value:blah}, false);
-            if (arguments.length == 3 && $.isObject(arguments[1])) {
-                return (arguments[2] == true) 
-                    ? $.format(this[arguments[0]], arguments[1])
-                    : $($.format(this[arguments[0]], arguments[1]));
-            }
-        }
-    };
-
-    var Argument = function(arg, args) {
-        this.__arg  = arg;
-        this.__args = args;
-        this.__max_precision = parseFloat('1.'+ (new Array(32)).join('1'), 10).toString().length-3;
-        this.__def_precision = 6;
-        this.getString = function(){
-            return this.__arg;
-        };
-        this.getKey = function(){
-            return this.__arg.split(':')[0];
-        };
-        this.getFormat = function(){
-            var match = this.getString().split(':');
-            return (match && match[1])? match[1]: 's';
-        };
-        this.getPrecision = function(){
-            var match = this.getFormat().match(/\.(\d+|\*)/g);
-            if (!match) { return this.__def_precision; }
-            else {
-                match = match[0].slice(1);
-                if (match != '*') { return parseInt(match, 10); }
-                else if(strings.strConversion.__getType(this.__args) == 'array') {
-                    return this.__args[1] && this.__args[0] || this.__def_precision;
-                }
-                else if(strings.strConversion.__getType(this.__args) == 'object') {
-                    return this.__args[this.getKey()] && this.__args[this.getKey()][0] || this.__def_precision;
-                }
-                else { return this.__def_precision; }
-            }
-        };
-        this.getPaddingLength = function(){
-            var match = false;
-            if (this.isAlternate()) {
-                match = this.getString().match(/0?#0?(\d+)/);
-                if (match && match[1]) { return parseInt(match[1], 10); }
-            }
-            match = this.getString().match(/(0|\.)(\d+|\*)/g);
-            return match && parseInt(match[0].slice(1), 10) || 0;
-        };
-        this.getPaddingString = function(){
-            var o = '';
-            if (this.isAlternate()) { o = ' '; }
-            // 0 take precedence on alternate format
-            if (this.getFormat().match(/#0|0#|^0|\.\d+/)) { o = '0'; }
-            return o;
-        };
-        this.getFlags = function(){
-            var match = this.getString().matc(/^(0|\#|\-|\+|\s)+/);
-            return match && match[0].split('') || [];
-        };
-        this.isAlternate = function() {
-            return !!this.getFormat().match(/^0?#/);
-        };
-    };
-
-    var arguments2Array = function(args, shift) {
-        var o = [];
-        for (l=args.length, x=(shift || 0)-1; x<l;x++) { o.push(args[x]); }
-        return o;
-    };
-    $.extend(strings);
-})(jQuery);
-
-/*
-  jQuery ui.timepickr - @VERSION
-  http://code.google.com/p/jquery-utils/
-
-  (c) Maxime Haineault <haineault at gmail.com> 
-  http://haineault.com
-
-  MIT License (http://www.opensource.org/licenses/mit-license.php
-
-  Note: if you want the original experimental plugin checkout the rev 224 
-
-  Dependencies
-  ------------
-  - jquery.utils.js
-  - jquery.strings.js
-  - jquery.ui.js
-  
-*/
-
-(function($) {
-
-$.tpl('timepickr.menu',   '<div class="ui-helper-reset ui-timepickr ui-widget" />');
-$.tpl('timepickr.row',    '<ol class="ui-timepickr-row ui-helper-clearfix" />');
-$.tpl('timepickr.button', '<li class="{className:s}"><span class="ui-state-default">{label:s}</span></li>');
-
-$.widget('ui.timepickr', {
-    plugins: {},
-    _create: function() {
-        this._dom = {
-            menu: $.tpl('timepickr.menu'),
-            row:  $.tpl('timepickr.menu')
-        };
-        this._trigger('initialize');
-        this._trigger('initialized');
-    },
-
-    _trigger: function(type, e, ui) {
-        var ui = ui || this;
-        $.ui.plugin.call(this, type, [e, ui]);
-        return $.Widget.prototype._trigger.call(this, type, e, ui);
-    },
-
-    _createButton: function(i, format, className) {
-        var o  = format && $.format(format, i) || i;
-        var cn = className && 'ui-timepickr-button '+ className || 'ui-timepickr-button';
-        return $.tpl('timepickr.button', {className: cn, label: o}).data('id', i)
-                .bind('mouseover', function(){
-                    $(this).siblings().find('span')
-                        .removeClass('ui-state-hover').end().end()
-                        .find('span').addClass('ui-state-hover');
-                });
-
-    },
-
-    _addRow: function(range, format, className, insertAfter) {
-        var ui  = this;
-        var btn = false;
-        var row = $.tpl('timepickr.row').bind('mouseover', function(){
-            $(this).next().show();
-        });
-        $.each(range, function(idx, val){
-            ui._createButton(val, format || false).appendTo(row);
-        });
-        if (className) {
-            $(row).addClass(className);
-        }
-        if (this.options.corners) {
-             row.find('span').addClass('ui-corner-'+ this.options.corners);
-        }
-        if (insertAfter) {
-            row.insertAfter(insertAfter);
-        }
-        else {
-            ui._dom.menu.append(row);
-        }
-        return row;
-    },
-
-    _setVal: function(val) {
-        val = val || this._getVal();
-        if (!(val.h==='' && val.m==='')) {        
-            this.element.data('timepickr.initialValue', val);
-            this.element.val(this._formatVal(val));        
-        }
-        if(this._dom.menu.is(':hidden')) {
-            this.element.trigger('change');
-        }
-    },
-
-    _getVal: function() {
-        var ols = this._dom.menu.find('ol');
-        function get(unit) {
-            var u = ols.filter('.'+unit).find('.ui-state-hover:first').text();
-            return u || ols.filter('.'+unit+'li:first span').text();
-        }
-        return {
-            h: get('hours'),
-            m: get('minutes'),
-            s: get('seconds'),
-            a: get('prefix'),
-            z: get('suffix'),
-            f: this.options['format'+ this.c],
-            c: this.c
-        };
-    },
-
-    _formatVal: function(ival) {
-        var val = ival || this._getVal();
-        val.c = this.options.convention;
-        val.f = val.c === 12 && this.options.format12 || this.options.format24;
-        return (new Time(val)).getTime();
-    },
-
-    blur: function() {
-        return this.element.blur();      
-    },
-
-    focus: function() {
-        return this.element.focus();      
-    },
-    show: function() {
-        this._trigger('show');
-        this.element.trigger(this.options.trigger);
-    },
-    hide: function() {
-        this._trigger('hide');
-        this._dom.menu.hide();
-    }
-
-});
-
-// These properties are shared accross every instances of timepickr 
-$.extend($.ui.timepickr.prototype, {
-    version:     '@VERSION',
-    //eventPrefix: '',
-    //getter:      '',
-    options:    {
-        convention:  24, // 24, 12
-        trigger:     'mouseover',
-        format12:    '{h:02.d}:{m:02.d} {z:s}',
-        format24:    '{h:02.d}:{m:02.d}',
-        hours:       true,
-        prefix:      ['am', 'pm'],
-        suffix:      ['am', 'pm'],
-        prefixVal:   false,
-        suffixVal:   true,
-        rangeHour12: $.range(1, 13),
-        rangeHour24: [$.range(0, 12), $.range(12, 24)],
-        rangeMin:    $.range(0, 60, 15),
-        rangeSec:    $.range(0, 60, 15),
-        corners:     'all',
-        // plugins
-        core:        true,
-        minutes:     true,
-        seconds:     false,
-        val:         false,
-        updateLive:  true,
-        resetOnBlur: true,
-        keyboardnav: true,
-        handle:      false,
-        handleEvent: 'click'
-    }
-});
-
-$.ui.plugin.add('timepickr', 'core', {
-    initialized: function(e, ui) {
-        var menu = ui._dom.menu;
-        var pos  = ui.element.position();
-
-        menu.insertAfter(ui.element).css('left', pos.left);
-
-        if (!$.boxModel) { // IE alignement fix
-            menu.css('margin-top', ui.element.height() + 8);
-        }
-        
-        ui.element
-            .bind(ui.options.trigger, function() {
-                ui._dom.menu.show();
-                ui._dom.menu.find('ol:first').show();
-                ui._trigger('focus');
-                if (ui.options.trigger != 'focus') {
-                    ui.element.focus();
-                }
-                ui._trigger('focus');
-            })
-            .bind('blur', function() {
-                ui.hide();
-                ui._trigger('blur');
-            });
-
-        menu.find('li').bind('mouseover.timepickr', function() {
-            ui._trigger('refresh');
-        });
-    },
-    refresh: function(e, ui) {
-        // Realign each menu layers
-        ui._dom.menu.find('ol').each(function(){
-            var p = $(this).prev('ol');
-            try { // .. to not fuckup IE
-                $(this).css('left', p.position().left + p.find('.ui-state-hover').position().left);
-            } catch(e) {};
-        });
-    }
-});
-
-$.ui.plugin.add('timepickr', 'hours', {
-    initialize: function(e, ui) {
-        if (ui.options.convention === 24) {
-            // prefix is required in 24h mode
-            ui._dom.prefix = ui._addRow(ui.options.prefix, false, 'prefix'); 
-
-            // split-range
-            if ($.isArray(ui.options.rangeHour24[0])) {
-                var range = [];
-                $.merge(range, ui.options.rangeHour24[0]);
-                $.merge(range, ui.options.rangeHour24[1]);
-                ui._dom.hours = ui._addRow(range, '{0:0.2d}', 'hours');
-                ui._dom.hours.find('li').slice(ui.options.rangeHour24[0].length, -1).hide();
-                var lis   = ui._dom.hours.find('li'); 
-
-                var show = [
-                    function() {
-                        lis.slice(ui.options.rangeHour24[0].length).hide().end()
-                           .slice(0, ui.options.rangeHour24[0].length).show()
-                           .filter(':visible:first').trigger('mouseover');
-
-                    },
-                    function() {
-                        lis.slice(0, ui.options.rangeHour24[0].length).hide().end()
-                           .slice(ui.options.rangeHour24[0].length).show()
-                           .filter(':visible:first').trigger('mouseover');
-                    }
-                ];
-
-                ui._dom.prefix.find('li').bind('mouseover.timepickr', function(){
-                    var index = ui._dom.menu.find('.prefix li').index(this);
-                    show[index].call();
-                });
-            }
-            else {
-                ui._dom.hours = ui._addRow(ui.options.rangeHour24, '{0:0.2d}', 'hours');
-                ui._dom.hours.find('li').slice(12, -1).hide();
-            }
-        }
-        else {
-            ui._dom.hours  = ui._addRow(ui.options.rangeHour12, '{0:0.2d}', 'hours');
-            // suffix is required in 12h mode
-            ui._dom.suffix = ui._addRow(ui.options.suffix, false, 'suffix'); 
-        }
-    }});
-
-$.ui.plugin.add('timepickr', 'minutes', {
-    initialize: function(e, ui) {
-        var p = ui._dom.hours && ui._dom.hours || false;
-        ui._dom.minutes = ui._addRow(ui.options.rangeMin, '{0:0.2d}', 'minutes', p);
-    }
-});
-
-$.ui.plugin.add('timepickr', 'seconds', {
-    initialize: function(e, ui) {
-        var p = ui._dom.minutes && ui._dom.minutes || false;
-        ui._dom.seconds = ui._addRow(ui.options.rangeSec, '{0:0.2d}', 'seconds', p);
-    }
-});
-
-$.ui.plugin.add('timepickr', 'val', {
-    initialized: function(e, ui) {
-        ui._setVal(ui.options.val);
-    }
-});
-
-$.ui.plugin.add('timepickr', 'updateLive', {
-    refresh: function(e, ui) {
-        ui._setVal();
-    }
-});
-
-$.ui.plugin.add('timepickr', 'resetOnBlur', {
-    initialized: function(e, ui) {
-        ui.element.data('timepickr.initialValue', ui._getVal());
-        ui._dom.menu.find('li > span').bind('mousedown.timepickr', function(){
-            ui.element.data('timepickr.initialValue', ui._getVal()); 
-        });
-    },
-    blur: function(e, ui) {
-        ui._setVal(ui.element.data('timepickr.initialValue'));
-    }
-});
-
-$.ui.plugin.add('timepickr', 'handle', {
-    initialized: function(e, ui) {
-        $(ui.options.handle).bind(ui.options.handleEvent + '.timepickr', function(){
-            ui.show();
-        });
-    }
-});
-
-$.ui.plugin.add('timepickr', 'keyboardnav', {
-    initialized: function(e, ui) {
-        ui.element
-            .bind('keydown', function(e) {
-                if ($.keyIs('enter', e)) {
-                    ui._setVal();
-                    ui.blur();
-                }
-                else if ($.keyIs('escape', e)) {
-                    ui.blur();
-                }
-            });
-    }
-});
-
-var Time = function() { // arguments: h, m, s, c, z, f || time string
-    if (!(this instanceof arguments.callee)) {
-        throw Error("Constructor called as a function");
-    }
-    // arguments as literal object
-    if (arguments.length == 1 && $.isObject(arguments[0])) {
-        this.h = arguments[0].h || 0;
-        this.m = arguments[0].m || 0;
-        this.s = arguments[0].s || 0;
-        this.c = arguments[0].c && ($.inArray(arguments[0].c, [12, 24]) >= 0) && arguments[0].c || 24;
-        this.f = arguments[0].f || ((this.c == 12) && '{h:02.d}:{m:02.d} {z:02.d}' || '{h:02.d}:{m:02.d}');
-        this.z = arguments[0].z || 'am';
-    }
-    // arguments as string
-    else if (arguments.length < 4 && $.isString(arguments[1])) {
-        this.c = arguments[2] && ($.inArray(arguments[0], [12, 24]) >= 0) && arguments[0] || 24;
-        this.f = arguments[3] || ((this.c == 12) && '{h:02.d}:{m:02.d} {z:02.d}' || '{h:02.d}:{m:02.d}');
-        this.z = arguments[4] || 'am';
-        
-        this.h = arguments[1] || 0; // parse
-        this.m = arguments[1] || 0; // parse
-        this.s = arguments[1] || 0; // parse
-    }
-    // no arguments (now)
-    else if (arguments.length === 0) {
-        // now
-    }
-    // standards arguments
-    else {
-        this.h = arguments[0] || 0;
-        this.m = arguments[1] || 0;
-        this.s = arguments[2] || 0;
-        this.c = arguments[3] && ($.inArray(arguments[3], [12, 24]) >= 0) && arguments[3] || 24;
-        this.f = this.f || ((this.c == 12) && '{h:02.d}:{m:02.d} {z:02.d}' || '{h:02.d}:{m:02.d}');
-        this.z = 'am';
-    }
-    return this;
-};
-
-Time.prototype.get        = function(p, f, u)    { return u && this.h || $.format(f, this.h); };
-Time.prototype.getHours   = function(unformated) { return this.get('h', '{0:02.d}', unformated); };
-Time.prototype.getMinutes = function(unformated) { return this.get('m', '{0:02.d}', unformated); };
-Time.prototype.getSeconds = function(unformated) { return this.get('s', '{0:02.d}', unformated); };
-Time.prototype.setFormat  = function(format)     { return this.f = format; };
-Time.prototype.getObject  = function()           { return { h: this.h, m: this.m, s: this.s, c: this.c, f: this.f, z: this.z }; };
-Time.prototype.getTime    = function()           { return $.format(this.f, {h: this.h, m: this.m, suffix: this.z}); }; // Thanks to Jackson for the fix.
-Time.prototype.parse      = function(str) { 
-    // 12h formats
-    if (this.c === 12) {
-        // Supported formats: (can't find any *official* standards for 12h..)
-        //  - [hh]:[mm]:[ss] [zz] | [hh]:[mm] [zz] | [hh] [zz] 
-        //  - [hh]:[mm]:[ss] [z.z.] | [hh]:[mm] [z.z.] | [hh] [z.z.]
-        this.tokens = str.split(/\s|:/);    
-        this.h = this.tokens[0] || 0;
-        this.m = this.tokens[1] || 0;
-        this.s = this.tokens[2] || 0;
-        this.z = this.tokens[3] || '';
-        return this.getObject();
-    }
-    // 24h formats
-    else { 
-        // Supported formats:
-        //  - ISO 8601: [hh][mm][ss] | [hh][mm] | [hh]  
-        //  - ISO 8601 extended: [hh]:[mm]:[ss] | [hh]:[mm] | [hh]
-        this.tokens = /:/.test(str) && str.split(/:/) || str.match(/[0-9]{2}/g);
-        this.h = this.tokens[0] || 0;
-        this.m = this.tokens[1] || 0;
-        this.s = this.tokens[2] || 0;
-        this.z = this.tokens[3] || '';
-        return this.getObject();
-    }
-};
-
-})(jQuery);
diff --git a/share/html/NoAuth/js/util.js b/share/html/NoAuth/js/util.js
index 346d457..cec511c 100644
--- a/share/html/NoAuth/js/util.js
+++ b/share/html/NoAuth/js/util.js
@@ -232,28 +232,37 @@ jQuery(function() {
         selectOtherMonths: true
     };
     jQuery(".ui-datepicker:not(.withtime)").datepicker(opts);
-    jQuery(".ui-datepicker.withtime").datepicker( jQuery.extend({}, opts, {
-        onSelect: function( dateText, inst ) {
-            // trigger timepicker to get time
-            var button = document.createElement('input');
-            button.setAttribute('type',  'button');
-            jQuery(button).width('5em');
-            jQuery(button).insertAfter(this);
-            jQuery(button).timepickr({val: '00:00'});
-            var date_input = this;
-
-            jQuery(button).blur( function() {
-                var time = jQuery(button).val();
-                if ( ! time.match(/\d\d:\d\d/) ) {
-                    time = '00:00';
-                }
-                jQuery(date_input).val(  dateText + ' ' + time + ':00' );
-                jQuery(button).remove();
-            } );
-
-            jQuery(button).focus();
-        }
-    }) );
+    jQuery(".ui-datepicker.withtime").datetimepicker( jQuery.extend({}, opts, {
+        stepHour: 1,
+        // We fake this by snapping below for the minute slider
+        //stepMinute: 5,
+        hourGrid: 6,
+        minuteGrid: 15,
+        showSecond: false,
+        timeFormat: 'hh:mm:ss',
+    }) ).each(function(index, el) {
+        var tp = jQuery.datepicker._get( jQuery.datepicker._getInst(el), 'timepicker');
+        if (!tp) return;
+
+        // Hook after _injectTimePicker so we can modify the minute_slider
+        // right after it's first created
+        tp._base_injectTimePicker = tp._injectTimePicker;
+        tp._injectTimePicker = function() {
+            this._base_injectTimePicker.apply(this, arguments);
+
+            // Now that we have minute_slider, modify it to be stepped for mouse movements
+            var slider = jQuery.data(this.minute_slider[0], "slider");
+            slider._base_normValueFromMouse = slider._normValueFromMouse;
+            slider._normValueFromMouse = function() {
+                var value           = this._base_normValueFromMouse.apply(this, arguments);
+                var old_step        = this.options.step;
+                this.options.step   = 5;
+                var aligned         = this._trimAlignValue( value );
+                this.options.step   = old_step;
+                return aligned;
+            };
+        };
+    });
 });
 
 function textToHTML(value) {

commit 75ad9e006125952c1c7c1f65ec92c6ae2ac08a3e
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Mon Oct 17 11:07:53 2011 -0400

    Add the new timepicker and jQuery UI JS to our third party sources
    
    The actual timepicker JS isn't minified in share/html/NoAuth/js, so I've
    just added a source for it in the README.

diff --git a/devel/third-party/README b/devel/third-party/README
index 876f134..2391517 100644
--- a/devel/third-party/README
+++ b/devel/third-party/README
@@ -21,3 +21,7 @@ jQuery UI Accordian component that goes into our minified jquery.ui-1.8.4.custom
 jquery.tablesorter.js
 http://tablesorter.com/jquery.tablesorter.js
 jQuery tablesorter plugin version 2.05b
+
+jquery-ui-timepicker-addon.js fae432b1
+https://github.com/trentrichardson/jQuery-Timepicker-Addon
+Timepicker integrated with the jQuery UI datepicker
diff --git a/devel/third-party/jquery.ui.mouse-1.8.4.js b/devel/third-party/jquery.ui.mouse-1.8.4.js
new file mode 100644
index 0000000..144bb80
--- /dev/null
+++ b/devel/third-party/jquery.ui.mouse-1.8.4.js
@@ -0,0 +1,151 @@
+/*!
+ * jQuery UI Mouse @VERSION
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Mouse
+ *
+ * Depends:
+ *	jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+$.widget("ui.mouse", {
+	options: {
+		cancel: ':input,option',
+		distance: 1,
+		delay: 0
+	},
+	_mouseInit: function() {
+		var self = this;
+
+		this.element
+			.bind('mousedown.'+this.widgetName, function(event) {
+				return self._mouseDown(event);
+			})
+			.bind('click.'+this.widgetName, function(event) {
+				if(self._preventClickEvent) {
+					self._preventClickEvent = false;
+					event.stopImmediatePropagation();
+					return false;
+				}
+			});
+
+		this.started = false;
+	},
+
+	// TODO: make sure destroying one instance of mouse doesn't mess with
+	// other instances of mouse
+	_mouseDestroy: function() {
+		this.element.unbind('.'+this.widgetName);
+	},
+
+	_mouseDown: function(event) {
+		// don't let more than one widget handle mouseStart
+		// TODO: figure out why we have to use originalEvent
+		event.originalEvent = event.originalEvent || {};
+		if (event.originalEvent.mouseHandled) { return; }
+
+		// we may have missed mouseup (out of window)
+		(this._mouseStarted && this._mouseUp(event));
+
+		this._mouseDownEvent = event;
+
+		var self = this,
+			btnIsLeft = (event.which == 1),
+			elIsCancel = (typeof this.options.cancel == "string" ? $(event.target).parents().add(event.target).filter(this.options.cancel).length : false);
+		if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) {
+			return true;
+		}
+
+		this.mouseDelayMet = !this.options.delay;
+		if (!this.mouseDelayMet) {
+			this._mouseDelayTimer = setTimeout(function() {
+				self.mouseDelayMet = true;
+			}, this.options.delay);
+		}
+
+		if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+			this._mouseStarted = (this._mouseStart(event) !== false);
+			if (!this._mouseStarted) {
+				event.preventDefault();
+				return true;
+			}
+		}
+
+		// these delegates are required to keep context
+		this._mouseMoveDelegate = function(event) {
+			return self._mouseMove(event);
+		};
+		this._mouseUpDelegate = function(event) {
+			return self._mouseUp(event);
+		};
+		$(document)
+			.bind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+			.bind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+
+		// preventDefault() is used to prevent the selection of text here -
+		// however, in Safari, this causes select boxes not to be selectable
+		// anymore, so this fix is needed
+		($.browser.safari || event.preventDefault());
+
+		event.originalEvent.mouseHandled = true;
+		return true;
+	},
+
+	_mouseMove: function(event) {
+		// IE mouseup check - mouseup happened when mouse was out of window
+		if ($.browser.msie && !event.button) {
+			return this._mouseUp(event);
+		}
+
+		if (this._mouseStarted) {
+			this._mouseDrag(event);
+			return event.preventDefault();
+		}
+
+		if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) {
+			this._mouseStarted =
+				(this._mouseStart(this._mouseDownEvent, event) !== false);
+			(this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event));
+		}
+
+		return !this._mouseStarted;
+	},
+
+	_mouseUp: function(event) {
+		$(document)
+			.unbind('mousemove.'+this.widgetName, this._mouseMoveDelegate)
+			.unbind('mouseup.'+this.widgetName, this._mouseUpDelegate);
+
+		if (this._mouseStarted) {
+			this._mouseStarted = false;
+			this._preventClickEvent = (event.target == this._mouseDownEvent.target);
+			this._mouseStop(event);
+		}
+
+		return false;
+	},
+
+	_mouseDistanceMet: function(event) {
+		return (Math.max(
+				Math.abs(this._mouseDownEvent.pageX - event.pageX),
+				Math.abs(this._mouseDownEvent.pageY - event.pageY)
+			) >= this.options.distance
+		);
+	},
+
+	_mouseDelayMet: function(event) {
+		return this.mouseDelayMet;
+	},
+
+	// These are placeholder methods, to be overriden by extending plugin
+	_mouseStart: function(event) {},
+	_mouseDrag: function(event) {},
+	_mouseStop: function(event) {},
+	_mouseCapture: function(event) { return true; }
+});
+
+})(jQuery);
diff --git a/devel/third-party/jquery.ui.slider-1.8.4.js b/devel/third-party/jquery.ui.slider-1.8.4.js
new file mode 100644
index 0000000..d90a794
--- /dev/null
+++ b/devel/third-party/jquery.ui.slider-1.8.4.js
@@ -0,0 +1,680 @@
+/*
+ * jQuery UI Slider @VERSION
+ *
+ * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ * http://jquery.org/license
+ *
+ * http://docs.jquery.com/UI/Slider
+ *
+ * Depends:
+ *	jquery.ui.core.js
+ *	jquery.ui.mouse.js
+ *	jquery.ui.widget.js
+ */
+(function( $, undefined ) {
+
+// number of pages in a slider
+// (how many times can you page up/down to go through the whole range)
+var numPages = 5;
+
+$.widget( "ui.slider", $.ui.mouse, {
+
+	widgetEventPrefix: "slide",
+
+	options: {
+		animate: false,
+		distance: 0,
+		max: 100,
+		min: 0,
+		orientation: "horizontal",
+		range: false,
+		step: 1,
+		value: 0,
+		values: null
+	},
+
+	_create: function() {
+		var self = this,
+			o = this.options;
+
+		this._keySliding = false;
+		this._mouseSliding = false;
+		this._animateOff = true;
+		this._handleIndex = null;
+		this._detectOrientation();
+		this._mouseInit();
+
+		this.element
+			.addClass( "ui-slider" +
+				" ui-slider-" + this.orientation +
+				" ui-widget" +
+				" ui-widget-content" +
+				" ui-corner-all" );
+		
+		if ( o.disabled ) {
+			this.element.addClass( "ui-slider-disabled ui-disabled" );
+		}
+
+		this.range = $([]);
+
+		if ( o.range ) {
+			if ( o.range === true ) {
+				this.range = $( "<div></div>" );
+				if ( !o.values ) {
+					o.values = [ this._valueMin(), this._valueMin() ];
+				}
+				if ( o.values.length && o.values.length !== 2 ) {
+					o.values = [ o.values[0], o.values[0] ];
+				}
+			} else {
+				this.range = $( "<div></div>" );
+			}
+
+			this.range
+				.appendTo( this.element )
+				.addClass( "ui-slider-range" );
+
+			if ( o.range === "min" || o.range === "max" ) {
+				this.range.addClass( "ui-slider-range-" + o.range );
+			}
+
+			// note: this isn't the most fittingly semantic framework class for this element,
+			// but worked best visually with a variety of themes
+			this.range.addClass( "ui-widget-header" );
+		}
+
+		if ( $( ".ui-slider-handle", this.element ).length === 0 ) {
+			$( "<a href='#'></a>" )
+				.appendTo( this.element )
+				.addClass( "ui-slider-handle" );
+		}
+
+		if ( o.values && o.values.length ) {
+			while ( $(".ui-slider-handle", this.element).length < o.values.length ) {
+				$( "<a href='#'></a>" )
+					.appendTo( this.element )
+					.addClass( "ui-slider-handle" );
+			}
+		}
+
+		this.handles = $( ".ui-slider-handle", this.element )
+			.addClass( "ui-state-default" +
+				" ui-corner-all" );
+
+		this.handle = this.handles.eq( 0 );
+
+		this.handles.add( this.range ).filter( "a" )
+			.click(function( event ) {
+				event.preventDefault();
+			})
+			.hover(function() {
+				if ( !o.disabled ) {
+					$( this ).addClass( "ui-state-hover" );
+				}
+			}, function() {
+				$( this ).removeClass( "ui-state-hover" );
+			})
+			.focus(function() {
+				if ( !o.disabled ) {
+					$( ".ui-slider .ui-state-focus" ).removeClass( "ui-state-focus" );
+					$( this ).addClass( "ui-state-focus" );
+				} else {
+					$( this ).blur();
+				}
+			})
+			.blur(function() {
+				$( this ).removeClass( "ui-state-focus" );
+			});
+
+		this.handles.each(function( i ) {
+			$( this ).data( "index.ui-slider-handle", i );
+		});
+
+		this.handles
+			.keydown(function( event ) {
+				var ret = true,
+					index = $( this ).data( "index.ui-slider-handle" ),
+					allowed,
+					curVal,
+					newVal,
+					step;
+	
+				if ( self.options.disabled ) {
+					return;
+				}
+	
+				switch ( event.keyCode ) {
+					case $.ui.keyCode.HOME:
+					case $.ui.keyCode.END:
+					case $.ui.keyCode.PAGE_UP:
+					case $.ui.keyCode.PAGE_DOWN:
+					case $.ui.keyCode.UP:
+					case $.ui.keyCode.RIGHT:
+					case $.ui.keyCode.DOWN:
+					case $.ui.keyCode.LEFT:
+						ret = false;
+						if ( !self._keySliding ) {
+							self._keySliding = true;
+							$( this ).addClass( "ui-state-active" );
+							allowed = self._start( event, index );
+							if ( allowed === false ) {
+								return;
+							}
+						}
+						break;
+				}
+	
+				step = self.options.step;
+				if ( self.options.values && self.options.values.length ) {
+					curVal = newVal = self.values( index );
+				} else {
+					curVal = newVal = self.value();
+				}
+	
+				switch ( event.keyCode ) {
+					case $.ui.keyCode.HOME:
+						newVal = self._valueMin();
+						break;
+					case $.ui.keyCode.END:
+						newVal = self._valueMax();
+						break;
+					case $.ui.keyCode.PAGE_UP:
+						newVal = self._trimAlignValue( curVal + ( (self._valueMax() - self._valueMin()) / numPages ) );
+						break;
+					case $.ui.keyCode.PAGE_DOWN:
+						newVal = self._trimAlignValue( curVal - ( (self._valueMax() - self._valueMin()) / numPages ) );
+						break;
+					case $.ui.keyCode.UP:
+					case $.ui.keyCode.RIGHT:
+						if ( curVal === self._valueMax() ) {
+							return;
+						}
+						newVal = self._trimAlignValue( curVal + step );
+						break;
+					case $.ui.keyCode.DOWN:
+					case $.ui.keyCode.LEFT:
+						if ( curVal === self._valueMin() ) {
+							return;
+						}
+						newVal = self._trimAlignValue( curVal - step );
+						break;
+				}
+	
+				self._slide( event, index, newVal );
+	
+				return ret;
+	
+			})
+			.keyup(function( event ) {
+				var index = $( this ).data( "index.ui-slider-handle" );
+	
+				if ( self._keySliding ) {
+					self._keySliding = false;
+					self._stop( event, index );
+					self._change( event, index );
+					$( this ).removeClass( "ui-state-active" );
+				}
+	
+			});
+
+		this._refreshValue();
+
+		this._animateOff = false;
+	},
+
+	destroy: function() {
+		this.handles.remove();
+		this.range.remove();
+
+		this.element
+			.removeClass( "ui-slider" +
+				" ui-slider-horizontal" +
+				" ui-slider-vertical" +
+				" ui-slider-disabled" +
+				" ui-widget" +
+				" ui-widget-content" +
+				" ui-corner-all" )
+			.removeData( "slider" )
+			.unbind( ".slider" );
+
+		this._mouseDestroy();
+
+		return this;
+	},
+
+	_mouseCapture: function( event ) {
+		var o = this.options,
+			position,
+			normValue,
+			distance,
+			closestHandle,
+			self,
+			index,
+			allowed,
+			offset,
+			mouseOverHandle;
+
+		if ( o.disabled ) {
+			return false;
+		}
+
+		this.elementSize = {
+			width: this.element.outerWidth(),
+			height: this.element.outerHeight()
+		};
+		this.elementOffset = this.element.offset();
+
+		position = { x: event.pageX, y: event.pageY };
+		normValue = this._normValueFromMouse( position );
+		distance = this._valueMax() - this._valueMin() + 1;
+		self = this;
+		this.handles.each(function( i ) {
+			var thisDistance = Math.abs( normValue - self.values(i) );
+			if ( distance > thisDistance ) {
+				distance = thisDistance;
+				closestHandle = $( this );
+				index = i;
+			}
+		});
+
+		// workaround for bug #3736 (if both handles of a range are at 0,
+		// the first is always used as the one with least distance,
+		// and moving it is obviously prevented by preventing negative ranges)
+		if( o.range === true && this.values(1) === o.min ) {
+			index += 1;
+			closestHandle = $( this.handles[index] );
+		}
+
+		allowed = this._start( event, index );
+		if ( allowed === false ) {
+			return false;
+		}
+		this._mouseSliding = true;
+
+		self._handleIndex = index;
+
+		closestHandle
+			.addClass( "ui-state-active" )
+			.focus();
+		
+		offset = closestHandle.offset();
+		mouseOverHandle = !$( event.target ).parents().andSelf().is( ".ui-slider-handle" );
+		this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
+			left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
+			top: event.pageY - offset.top -
+				( closestHandle.height() / 2 ) -
+				( parseInt( closestHandle.css("borderTopWidth"), 10 ) || 0 ) -
+				( parseInt( closestHandle.css("borderBottomWidth"), 10 ) || 0) +
+				( parseInt( closestHandle.css("marginTop"), 10 ) || 0)
+		};
+
+		this._slide( event, index, normValue );
+		this._animateOff = true;
+		return true;
+	},
+
+	_mouseStart: function( event ) {
+		return true;
+	},
+
+	_mouseDrag: function( event ) {
+		var position = { x: event.pageX, y: event.pageY },
+			normValue = this._normValueFromMouse( position );
+		
+		this._slide( event, this._handleIndex, normValue );
+
+		return false;
+	},
+
+	_mouseStop: function( event ) {
+		this.handles.removeClass( "ui-state-active" );
+		this._mouseSliding = false;
+
+		this._stop( event, this._handleIndex );
+		this._change( event, this._handleIndex );
+
+		this._handleIndex = null;
+		this._clickOffset = null;
+		this._animateOff = false;
+
+		return false;
+	},
+	
+	_detectOrientation: function() {
+		this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
+	},
+
+	_normValueFromMouse: function( position ) {
+		var pixelTotal,
+			pixelMouse,
+			percentMouse,
+			valueTotal,
+			valueMouse;
+
+		if ( this.orientation === "horizontal" ) {
+			pixelTotal = this.elementSize.width;
+			pixelMouse = position.x - this.elementOffset.left - ( this._clickOffset ? this._clickOffset.left : 0 );
+		} else {
+			pixelTotal = this.elementSize.height;
+			pixelMouse = position.y - this.elementOffset.top - ( this._clickOffset ? this._clickOffset.top : 0 );
+		}
+
+		percentMouse = ( pixelMouse / pixelTotal );
+		if ( percentMouse > 1 ) {
+			percentMouse = 1;
+		}
+		if ( percentMouse < 0 ) {
+			percentMouse = 0;
+		}
+		if ( this.orientation === "vertical" ) {
+			percentMouse = 1 - percentMouse;
+		}
+
+		valueTotal = this._valueMax() - this._valueMin();
+		valueMouse = this._valueMin() + percentMouse * valueTotal;
+
+		return this._trimAlignValue( valueMouse );
+	},
+
+	_start: function( event, index ) {
+		var uiHash = {
+			handle: this.handles[ index ],
+			value: this.value()
+		};
+		if ( this.options.values && this.options.values.length ) {
+			uiHash.value = this.values( index );
+			uiHash.values = this.values();
+		}
+		return this._trigger( "start", event, uiHash );
+	},
+
+	_slide: function( event, index, newVal ) {
+		var otherVal,
+			newValues,
+			allowed;
+
+		if ( this.options.values && this.options.values.length ) {
+			otherVal = this.values( index ? 0 : 1 );
+
+			if ( ( this.options.values.length === 2 && this.options.range === true ) && 
+					( ( index === 0 && newVal > otherVal) || ( index === 1 && newVal < otherVal ) )
+				) {
+				newVal = otherVal;
+			}
+
+			if ( newVal !== this.values( index ) ) {
+				newValues = this.values();
+				newValues[ index ] = newVal;
+				// A slide can be canceled by returning false from the slide callback
+				allowed = this._trigger( "slide", event, {
+					handle: this.handles[ index ],
+					value: newVal,
+					values: newValues
+				} );
+				otherVal = this.values( index ? 0 : 1 );
+				if ( allowed !== false ) {
+					this.values( index, newVal, true );
+				}
+			}
+		} else {
+			if ( newVal !== this.value() ) {
+				// A slide can be canceled by returning false from the slide callback
+				allowed = this._trigger( "slide", event, {
+					handle: this.handles[ index ],
+					value: newVal
+				} );
+				if ( allowed !== false ) {
+					this.value( newVal );
+				}
+			}
+		}
+	},
+
+	_stop: function( event, index ) {
+		var uiHash = {
+			handle: this.handles[ index ],
+			value: this.value()
+		};
+		if ( this.options.values && this.options.values.length ) {
+			uiHash.value = this.values( index );
+			uiHash.values = this.values();
+		}
+
+		this._trigger( "stop", event, uiHash );
+	},
+
+	_change: function( event, index ) {
+		if ( !this._keySliding && !this._mouseSliding ) {
+			var uiHash = {
+				handle: this.handles[ index ],
+				value: this.value()
+			};
+			if ( this.options.values && this.options.values.length ) {
+				uiHash.value = this.values( index );
+				uiHash.values = this.values();
+			}
+
+			this._trigger( "change", event, uiHash );
+		}
+	},
+
+	value: function( newValue ) {
+		if ( arguments.length ) {
+			this.options.value = this._trimAlignValue( newValue );
+			this._refreshValue();
+			this._change( null, 0 );
+		}
+
+		return this._value();
+	},
+
+	values: function( index, newValue ) {
+		var vals,
+			newValues,
+			i;
+
+		if ( arguments.length > 1 ) {
+			this.options.values[ index ] = this._trimAlignValue( newValue );
+			this._refreshValue();
+			this._change( null, index );
+		}
+
+		if ( arguments.length ) {
+			if ( $.isArray( arguments[ 0 ] ) ) {
+				vals = this.options.values;
+				newValues = arguments[ 0 ];
+				for ( i = 0; i < vals.length; i += 1 ) {
+					vals[ i ] = this._trimAlignValue( newValues[ i ] );
+					this._change( null, i );
+				}
+				this._refreshValue();
+			} else {
+				if ( this.options.values && this.options.values.length ) {
+					return this._values( index );
+				} else {
+					return this.value();
+				}
+			}
+		} else {
+			return this._values();
+		}
+	},
+
+	_setOption: function( key, value ) {
+		var i,
+			valsLength = 0;
+
+		if ( $.isArray( this.options.values ) ) {
+			valsLength = this.options.values.length;
+		}
+
+		$.Widget.prototype._setOption.apply( this, arguments );
+
+		switch ( key ) {
+			case "disabled":
+				if ( value ) {
+					this.handles.filter( ".ui-state-focus" ).blur();
+					this.handles.removeClass( "ui-state-hover" );
+					this.handles.attr( "disabled", "disabled" );
+					this.element.addClass( "ui-disabled" );
+				} else {
+					this.handles.removeAttr( "disabled" );
+					this.element.removeClass( "ui-disabled" );
+				}
+				break;
+			case "orientation":
+				this._detectOrientation();
+				this.element
+					.removeClass( "ui-slider-horizontal ui-slider-vertical" )
+					.addClass( "ui-slider-" + this.orientation );
+				this._refreshValue();
+				break;
+			case "value":
+				this._animateOff = true;
+				this._refreshValue();
+				this._change( null, 0 );
+				this._animateOff = false;
+				break;
+			case "values":
+				this._animateOff = true;
+				this._refreshValue();
+				for ( i = 0; i < valsLength; i += 1 ) {
+					this._change( null, i );
+				}
+				this._animateOff = false;
+				break;
+		}
+	},
+
+	//internal value getter
+	// _value() returns value trimmed by min and max, aligned by step
+	_value: function() {
+		var val = this.options.value;
+		val = this._trimAlignValue( val );
+
+		return val;
+	},
+
+	//internal values getter
+	// _values() returns array of values trimmed by min and max, aligned by step
+	// _values( index ) returns single value trimmed by min and max, aligned by step
+	_values: function( index ) {
+		var val,
+			vals,
+			i;
+
+		if ( arguments.length ) {
+			val = this.options.values[ index ];
+			val = this._trimAlignValue( val );
+
+			return val;
+		} else {
+			// .slice() creates a copy of the array
+			// this copy gets trimmed by min and max and then returned
+			vals = this.options.values.slice();
+			for ( i = 0; i < vals.length; i+= 1) {
+				vals[ i ] = this._trimAlignValue( vals[ i ] );
+			}
+
+			return vals;
+		}
+	},
+	
+	// returns the step-aligned value that val is closest to, between (inclusive) min and max
+	_trimAlignValue: function( val ) {
+		if ( val < this._valueMin() ) {
+			return this._valueMin();
+		}
+		if ( val > this._valueMax() ) {
+			return this._valueMax();
+		}
+		var step = ( this.options.step > 0 ) ? this.options.step : 1,
+			valModStep = val % step,
+			alignValue = val - valModStep;
+
+		if ( Math.abs(valModStep) * 2 >= step ) {
+			alignValue += ( valModStep > 0 ) ? step : ( -step );
+		}
+
+		// Since JavaScript has problems with large floats, round
+		// the final value to 5 digits after the decimal point (see #4124)
+		return parseFloat( alignValue.toFixed(5) );
+	},
+
+	_valueMin: function() {
+		return this.options.min;
+	},
+
+	_valueMax: function() {
+		return this.options.max;
+	},
+	
+	_refreshValue: function() {
+		var oRange = this.options.range,
+			o = this.options,
+			self = this,
+			animate = ( !this._animateOff ) ? o.animate : false,
+			valPercent,
+			_set = {},
+			lastValPercent,
+			value,
+			valueMin,
+			valueMax;
+
+		if ( this.options.values && this.options.values.length ) {
+			this.handles.each(function( i, j ) {
+				valPercent = ( self.values(i) - self._valueMin() ) / ( self._valueMax() - self._valueMin() ) * 100;
+				_set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+				$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+				if ( self.options.range === true ) {
+					if ( self.orientation === "horizontal" ) {
+						if ( i === 0 ) {
+							self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { left: valPercent + "%" }, o.animate );
+						}
+						if ( i === 1 ) {
+							self.range[ animate ? "animate" : "css" ]( { width: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+						}
+					} else {
+						if ( i === 0 ) {
+							self.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { bottom: ( valPercent ) + "%" }, o.animate );
+						}
+						if ( i === 1 ) {
+							self.range[ animate ? "animate" : "css" ]( { height: ( valPercent - lastValPercent ) + "%" }, { queue: false, duration: o.animate } );
+						}
+					}
+				}
+				lastValPercent = valPercent;
+			});
+		} else {
+			value = this.value();
+			valueMin = this._valueMin();
+			valueMax = this._valueMax();
+			valPercent = ( valueMax !== valueMin ) ?
+					( value - valueMin ) / ( valueMax - valueMin ) * 100 :
+					0;
+			_set[ self.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
+			this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
+
+			if ( oRange === "min" && this.orientation === "horizontal" ) {
+				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { width: valPercent + "%" }, o.animate );
+			}
+			if ( oRange === "max" && this.orientation === "horizontal" ) {
+				this.range[ animate ? "animate" : "css" ]( { width: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+			}
+			if ( oRange === "min" && this.orientation === "vertical" ) {
+				this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( { height: valPercent + "%" }, o.animate );
+			}
+			if ( oRange === "max" && this.orientation === "vertical" ) {
+				this.range[ animate ? "animate" : "css" ]( { height: ( 100 - valPercent ) + "%" }, { queue: false, duration: o.animate } );
+			}
+		}
+	}
+
+});
+
+$.extend( $.ui.slider, {
+	version: "@VERSION"
+});
+
+}(jQuery));

commit 6f5787e9a70fb8a473b059cd0c430ff0bdb2f725
Author: Thomas Sibley <trs at bestpractical.com>
Date:   Fri Feb 3 14:01:09 2012 -0500

    Don't shift the datetime picker up if it would hit the bottom
    
    Shifting it up weirdly covers up the input and sometimes runs into
    z-index problems with the aileron menus.
    
    The datetime picker now extends past the viewport bottom and will push
    the page taller if it hits the page bottom.  This requires a short
    scroll, but is preferable to inconsistent and awful looking alignment
    otherwise.

diff --git a/share/html/NoAuth/js/jquery-ui-patch-datepicker.js b/share/html/NoAuth/js/jquery-ui-patch-datepicker.js
index 6eca467..38d537a 100644
--- a/share/html/NoAuth/js/jquery-ui-patch-datepicker.js
+++ b/share/html/NoAuth/js/jquery-ui-patch-datepicker.js
@@ -58,4 +58,23 @@
 
         return data;
     };
+
+    $.datepicker._checkOffset_orig = $.datepicker._checkOffset;
+    $.datepicker._checkOffset = function(inst, offset, isFixed) {
+        // copied from the original
+        var dpHeight    = inst.dpDiv.outerHeight();
+        var inputHeight = inst.input ? inst.input.outerHeight() : 0;
+        var viewHeight  = document.documentElement.clientHeight + $(document).scrollTop();
+
+        // save the original offset rather than the new offset because the
+        // original function modifies the passed arg as a side-effect
+        var old_offset = { top: offset.top, left: offset.left };
+        offset = $.datepicker._checkOffset_orig(inst, offset, isFixed);
+
+        // Negate any up or down positioning by adding instead of subtracting
+        offset.top += Math.min(old_offset.top, (old_offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
+            Math.abs(dpHeight + inputHeight) : 0);
+
+        return offset;
+    };
 })(jQuery);

commit d5c04c62e57ba7a8c6eedcfdcc691677bf129b85
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Thu Jun 21 18:13:24 2012 -0400

    Make the "Now" button in the timepicker look less disabled

diff --git a/share/html/NoAuth/css/base/jquery-ui-timepicker-addon.css b/share/html/NoAuth/css/base/jquery-ui-timepicker-addon.css
index 71e4c46..b4837d6 100644
--- a/share/html/NoAuth/css/base/jquery-ui-timepicker-addon.css
+++ b/share/html/NoAuth/css/base/jquery-ui-timepicker-addon.css
@@ -4,3 +4,4 @@
 .ui-timepicker-div dl dd { margin: -25px 10px 10px 65px; }
 .ui-timepicker-div td { font-size: 90%; }
 .ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
+.ui-datepicker-buttonpane button.ui-datepicker-current { opacity: 1.0; }

commit 1b2787b1bb87897eb1e93f817eb8581a1850ce8f
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Thu Jun 21 16:46:59 2012 -0400

    Patch timepicker to not force the textbox to update on click-away
    
    Hotpatch the timepicker to remove the part of the onClose method which
    forces an unnecessary update from the timepicker.  This allows the user
    to type "tomorrow" into the textarea, and have it accepted when the user
    clicks clicks away and the datetime picker closes.  This is particularly
    important given that the accepted way to remove a due date is to enter
    "0" or " " into the input.

diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index 59bd64a..79b1249 100755
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -866,8 +866,8 @@ Set(@JSFiles, qw/
     jquery-1.4.2.min.js
     jquery_noconflict.js
     jquery-ui-1.8.4.custom.min.js
-    jquery-ui-patch-datepicker.js
     jquery-ui-timepicker-addon.js
+    jquery-ui-patch-datepicker.js
     titlebox-state.js
     util.js
     userautocomplete.js
diff --git a/share/html/NoAuth/js/jquery-ui-patch-datepicker.js b/share/html/NoAuth/js/jquery-ui-patch-datepicker.js
index 38d537a..c6497b2 100644
--- a/share/html/NoAuth/js/jquery-ui-patch-datepicker.js
+++ b/share/html/NoAuth/js/jquery-ui-patch-datepicker.js
@@ -77,4 +77,16 @@
 
         return offset;
     };
+
+
+    $.timepicker._newInst_orig = $.timepicker._newInst;
+    $.timepicker._newInst = function($input, o) {
+        var tp_inst = $.timepicker._newInst_orig($input, o);
+        tp_inst._defaults.onClose = function(dateText, dp_inst) {
+	    if ($.isFunction(o.onClose))
+		o.onClose.call($input[0], dateText, dp_inst, tp_inst);
+        };
+        return tp_inst;
+    };
+
 })(jQuery);

commit fbd54024abb01247fbc78febf10a7552cf7cd675
Author: Alex Vandiver <alexmv at bestpractical.com>
Date:   Mon Jun 25 17:34:54 2012 -0400

    Make "Today" button work on date inputs when timepicker is installed
    
    The timepicker attempts to override the "Today" button in the usual
    datepicker to add a timestamp.  However, this fails with javascript
    errors ("Cannot read property '_defaults' of undefined") if the
    timepicker has not been instantiated on that element.
    
    Backport timepicker's 3ac151f commit from upstream which fixes this
    problem.

diff --git a/share/html/NoAuth/js/jquery-ui-timepicker-addon.js b/share/html/NoAuth/js/jquery-ui-timepicker-addon.js
index ec4b577..72abe04 100644
--- a/share/html/NoAuth/js/jquery-ui-timepicker-addon.js
+++ b/share/html/NoAuth/js/jquery-ui-timepicker-addon.js
@@ -1047,7 +1047,7 @@ $.datepicker._gotoToday = function(id) {
 	this._base_gotoToday(id);
 	var now = new Date();
 	var tp_inst = this._get(inst, 'timepicker');
-	if (tp_inst._defaults.showTimezone && tp_inst.timezone_select) {
+	if (tp_inst && tp_inst._defaults.showTimezone && tp_inst.timezone_select) {
 		var tzoffset = now.getTimezoneOffset(); // If +0100, returns -60
 		var tzsign = tzoffset > 0 ? '-' : '+';
 		tzoffset = Math.abs(tzoffset);

-----------------------------------------------------------------------


More information about the Rt-commit mailing list