summaryrefslogtreecommitdiff
path: root/lib/dijit/_TimePicker.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dijit/_TimePicker.js')
-rw-r--r--lib/dijit/_TimePicker.js726
1 files changed, 471 insertions, 255 deletions
diff --git a/lib/dijit/_TimePicker.js b/lib/dijit/_TimePicker.js
index fc3ae29a8..678223c45 100644
--- a/lib/dijit/_TimePicker.js
+++ b/lib/dijit/_TimePicker.js
@@ -1,265 +1,481 @@
/*
- Copyright (c) 2004-2010, The Dojo Foundation All Rights Reserved.
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
Available via Academic Free License >= 2.1 OR the modified BSD license.
see: http://dojotoolkit.org/license for details
*/
-if(!dojo._hasResource["dijit._TimePicker"]){
-dojo._hasResource["dijit._TimePicker"]=true;
+if(!dojo._hasResource["dijit._TimePicker"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dijit._TimePicker"] = true;
dojo.provide("dijit._TimePicker");
dojo.require("dijit.form._FormWidget");
dojo.require("dojo.date.locale");
-dojo.declare("dijit._TimePicker",[dijit._Widget,dijit._Templated],{templateString:dojo.cache("dijit","templates/TimePicker.html","<div id=\"widget_${id}\" class=\"dijitMenu\"\n ><div dojoAttachPoint=\"upArrow\" class=\"dijitButtonNode dijitUpArrowButton\" dojoAttachEvent=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" wairole=\"presentation\" role=\"presentation\">&nbsp;</div\n\t\t><div class=\"dijitArrowButtonChar\">&#9650;</div></div\n ><div dojoAttachPoint=\"timeMenu,focusNode\" dojoAttachEvent=\"onclick:_onOptionSelected,onmouseover,onmouseout\"></div\n ><div dojoAttachPoint=\"downArrow\" class=\"dijitButtonNode dijitDownArrowButton\" dojoAttachEvent=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" wairole=\"presentation\" role=\"presentation\">&nbsp;</div\n\t\t><div class=\"dijitArrowButtonChar\">&#9660;</div></div\n></div>\n"),baseClass:"dijitTimePicker",clickableIncrement:"T00:15:00",visibleIncrement:"T01:00:00",visibleRange:"T05:00:00",value:new Date(),_visibleIncrement:2,_clickableIncrement:1,_totalIncrements:10,constraints:{},serialize:dojo.date.stamp.toISOString,_filterString:"",setValue:function(_1){
-dojo.deprecated("dijit._TimePicker:setValue() is deprecated. Use set('value', ...) instead.","","2.0");
-this.set("value",_1);
-},_setValueAttr:function(_2){
-this.value=_2;
-this._showText();
-},onOpen:function(_3){
-if(this._beenOpened&&this.domNode.parentNode){
-var p=dijit.byId(this.domNode.parentNode.dijitPopupParent);
-if(p){
-var _4=p.get("displayedValue");
-if(_4&&!p.parse(_4,p.constraints)){
-this._filterString=_4;
-}else{
-this._filterString="";
-}
-this._showText();
-}
-}
-this._beenOpened=true;
-},isDisabledDate:function(_5,_6){
-return false;
-},_getFilteredNodes:function(_7,_8,_9){
-var _a=[],n,i=_7,_b=this._maxIncrement+Math.abs(i),_c=_9?-1:1,_d=_9?1:0,_e=_9?0:1;
-do{
-i=i-_d;
-n=this._createOption(i);
-if(n){
-_a.push(n);
-}
-i=i+_e;
-}while(_a.length<_8&&(i*_c)<_b);
-if(_9){
-_a.reverse();
-}
-return _a;
-},_showText:function(){
-this.timeMenu.innerHTML="";
-var _f=dojo.date.stamp.fromISOString;
-this._clickableIncrementDate=_f(this.clickableIncrement);
-this._visibleIncrementDate=_f(this.visibleIncrement);
-this._visibleRangeDate=_f(this.visibleRange);
-var _10=function(_11){
-return _11.getHours()*60*60+_11.getMinutes()*60+_11.getSeconds();
-};
-var _12=_10(this._clickableIncrementDate);
-var _13=_10(this._visibleIncrementDate);
-var _14=_10(this._visibleRangeDate);
-var _15=this.value.getTime();
-this._refDate=new Date(_15-_15%(_13*1000));
-this._refDate.setFullYear(1970,0,1);
-this._clickableIncrement=1;
-this._totalIncrements=_14/_12;
-this._visibleIncrement=_13/_12;
-this._maxIncrement=(60*60*24)/_12;
-var _16=this._getFilteredNodes(0,this._totalIncrements>>1,true);
-var _17=this._getFilteredNodes(0,this._totalIncrements>>1,false);
-if(_16.length<this._totalIncrements>>1){
-_16=_16.slice(_16.length/2);
-_17=_17.slice(0,_17.length/2);
-}
-dojo.forEach(_16.concat(_17),function(n){
-this.timeMenu.appendChild(n);
-},this);
-},postCreate:function(){
-if(this.constraints===dijit._TimePicker.prototype.constraints){
-this.constraints={};
-}
-dojo.mixin(this,this.constraints);
-if(!this.constraints.locale){
-this.constraints.locale=this.lang;
-}
-this.connect(this.timeMenu,dojo.isIE?"onmousewheel":"DOMMouseScroll","_mouseWheeled");
-var _18=this;
-var _19=function(){
-_18._connects.push(dijit.typematic.addMouseListener.apply(null,arguments));
-};
-_19(this.upArrow,this,this._onArrowUp,1,50);
-_19(this.downArrow,this,this._onArrowDown,1,50);
-var _1a=function(cb){
-return function(cnt){
-if(cnt>0){
-cb.call(this,arguments);
-}
-};
-};
-var _1b=function(_1c,cb){
-return function(e){
-dojo.stopEvent(e);
-dijit.typematic.trigger(e,this,_1c,_1a(cb),_1c,1,50);
-};
-};
-this.connect(this.upArrow,"onmouseover",_1b(this.upArrow,this._onArrowUp));
-this.connect(this.downArrow,"onmouseover",_1b(this.downArrow,this._onArrowDown));
-this.inherited(arguments);
-},_buttonMouse:function(e){
-dojo.toggleClass(e.currentTarget,e.currentTarget==this.upArrow?"dijitUpArrowHover":"dijitDownArrowHover",e.type=="mouseenter"||e.type=="mouseover");
-},_createOption:function(_1d){
-var _1e=new Date(this._refDate);
-var _1f=this._clickableIncrementDate;
-_1e.setHours(_1e.getHours()+_1f.getHours()*_1d,_1e.getMinutes()+_1f.getMinutes()*_1d,_1e.getSeconds()+_1f.getSeconds()*_1d);
-if(this.constraints.selector=="time"){
-_1e.setFullYear(1970,0,1);
-}
-var _20=dojo.date.locale.format(_1e,this.constraints);
-if(this._filterString&&_20.toLowerCase().indexOf(this._filterString)!==0){
-return null;
-}
-var div=dojo.create("div",{"class":this.baseClass+"Item"});
-div.date=_1e;
-div.index=_1d;
-dojo.create("div",{"class":this.baseClass+"ItemInner",innerHTML:_20},div);
-if(_1d%this._visibleIncrement<1&&_1d%this._visibleIncrement>-1){
-dojo.addClass(div,this.baseClass+"Marker");
-}else{
-if(!(_1d%this._clickableIncrement)){
-dojo.addClass(div,this.baseClass+"Tick");
-}
-}
-if(this.isDisabledDate(_1e)){
-dojo.addClass(div,this.baseClass+"ItemDisabled");
-}
-if(!dojo.date.compare(this.value,_1e,this.constraints.selector)){
-div.selected=true;
-dojo.addClass(div,this.baseClass+"ItemSelected");
-if(dojo.hasClass(div,this.baseClass+"Marker")){
-dojo.addClass(div,this.baseClass+"MarkerSelected");
-}else{
-dojo.addClass(div,this.baseClass+"TickSelected");
-}
-}
-return div;
-},_onOptionSelected:function(tgt){
-var _21=tgt.target.date||tgt.target.parentNode.date;
-if(!_21||this.isDisabledDate(_21)){
-return;
-}
-this._highlighted_option=null;
-this.set("value",_21);
-this.onValueSelected(_21);
-},onValueSelected:function(_22){
-},_highlightOption:function(_23,_24){
-if(!_23){
-return;
-}
-if(_24){
-if(this._highlighted_option){
-this._highlightOption(this._highlighted_option,false);
-}
-this._highlighted_option=_23;
-}else{
-if(this._highlighted_option!==_23){
-return;
-}else{
-this._highlighted_option=null;
-}
-}
-dojo.toggleClass(_23,this.baseClass+"ItemHover",_24);
-if(dojo.hasClass(_23,this.baseClass+"Marker")){
-dojo.toggleClass(_23,this.baseClass+"MarkerHover",_24);
-}else{
-dojo.toggleClass(_23,this.baseClass+"TickHover",_24);
-}
-},onmouseover:function(e){
-this._keyboardSelected=null;
-var tgr=(e.target.parentNode===this.timeMenu)?e.target:e.target.parentNode;
-if(!dojo.hasClass(tgr,this.baseClass+"Item")){
-return;
-}
-this._highlightOption(tgr,true);
-},onmouseout:function(e){
-this._keyboardSelected=null;
-var tgr=(e.target.parentNode===this.timeMenu)?e.target:e.target.parentNode;
-this._highlightOption(tgr,false);
-},_mouseWheeled:function(e){
-this._keyboardSelected=null;
-dojo.stopEvent(e);
-var _25=(dojo.isIE?e.wheelDelta:-e.detail);
-this[(_25>0?"_onArrowUp":"_onArrowDown")]();
-},_onArrowUp:function(_26){
-if(typeof _26=="number"&&_26==-1){
-return;
-}
-if(!this.timeMenu.childNodes.length){
-return;
-}
-var _27=this.timeMenu.childNodes[0].index;
-var _28=this._getFilteredNodes(_27,1,true);
-if(_28.length){
-this.timeMenu.removeChild(this.timeMenu.childNodes[this.timeMenu.childNodes.length-1]);
-this.timeMenu.insertBefore(_28[0],this.timeMenu.childNodes[0]);
-}
-},_onArrowDown:function(_29){
-if(typeof _29=="number"&&_29==-1){
-return;
-}
-if(!this.timeMenu.childNodes.length){
-return;
-}
-var _2a=this.timeMenu.childNodes[this.timeMenu.childNodes.length-1].index+1;
-var _2b=this._getFilteredNodes(_2a,1,false);
-if(_2b.length){
-this.timeMenu.removeChild(this.timeMenu.childNodes[0]);
-this.timeMenu.appendChild(_2b[0]);
-}
-},handleKey:function(e){
-var dk=dojo.keys;
-if(e.keyChar||e.charOrCode===dk.BACKSPACE||e.charOrCode==dk.DELETE){
-setTimeout(dojo.hitch(this,function(){
-this._filterString=e.target.value.toLowerCase();
-this._showText();
-}),1);
-}else{
-if(e.charOrCode==dk.DOWN_ARROW||e.charOrCode==dk.UP_ARROW){
-dojo.stopEvent(e);
-if(this._highlighted_option&&!this._highlighted_option.parentNode){
-this._highlighted_option=null;
-}
-var _2c=this.timeMenu,tgt=this._highlighted_option||dojo.query("."+this.baseClass+"ItemSelected",_2c)[0];
-if(!tgt){
-tgt=_2c.childNodes[0];
-}else{
-if(_2c.childNodes.length){
-if(e.charOrCode==dk.DOWN_ARROW&&!tgt.nextSibling){
-this._onArrowDown();
-}else{
-if(e.charOrCode==dk.UP_ARROW&&!tgt.previousSibling){
-this._onArrowUp();
-}
-}
-if(e.charOrCode==dk.DOWN_ARROW){
-tgt=tgt.nextSibling;
-}else{
-tgt=tgt.previousSibling;
-}
-}
-}
-this._highlightOption(tgt,true);
-this._keyboardSelected=tgt;
-}else{
-if(this._highlighted_option&&(e.charOrCode==dk.ENTER||e.charOrCode===dk.TAB)){
-if(!this._keyboardSelected&&e.charOrCode===dk.TAB){
-return;
-}
-if(e.charOrCode==dk.ENTER){
-dojo.stopEvent(e);
-}
-this._onOptionSelected({target:this._highlighted_option});
-}
-}
-}
-}});
+
+
+/*=====
+dojo.declare(
+ "dijit._TimePicker.__Constraints",
+ dojo.date.locale.__FormatOptions,
+ {
+ // clickableIncrement: String
+ // See `dijit._TimePicker.clickableIncrement`
+ clickableIncrement: "T00:15:00",
+
+ // visibleIncrement: String
+ // See `dijit._TimePicker.visibleIncrement`
+ visibleIncrement: "T01:00:00",
+
+ // visibleRange: String
+ // See `dijit._TimePicker.visibleRange`
+ visibleRange: "T05:00:00"
+ }
+);
+=====*/
+
+dojo.declare("dijit._TimePicker",
+ [dijit._Widget, dijit._Templated],
+ {
+ // summary:
+ // A graphical time picker.
+ // This widget is used internally by other widgets and is not available
+ // as a standalone widget due to lack of accessibility support.
+
+ templateString: dojo.cache("dijit", "templates/TimePicker.html", "<div id=\"widget_${id}\" class=\"dijitMenu\"\n ><div dojoAttachPoint=\"upArrow\" class=\"dijitButtonNode dijitUpArrowButton\" dojoAttachEvent=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" role=\"presentation\">&nbsp;</div\n\t\t><div class=\"dijitArrowButtonChar\">&#9650;</div></div\n ><div dojoAttachPoint=\"timeMenu,focusNode\" dojoAttachEvent=\"onclick:_onOptionSelected,onmouseover,onmouseout\"></div\n ><div dojoAttachPoint=\"downArrow\" class=\"dijitButtonNode dijitDownArrowButton\" dojoAttachEvent=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" role=\"presentation\">&nbsp;</div\n\t\t><div class=\"dijitArrowButtonChar\">&#9660;</div></div\n></div>\n"),
+
+ // baseClass: [protected] String
+ // The root className to use for the various states of this widget
+ baseClass: "dijitTimePicker",
+
+ // clickableIncrement: String
+ // ISO-8601 string representing the amount by which
+ // every clickable element in the time picker increases.
+ // Set in local time, without a time zone.
+ // Example: `T00:15:00` creates 15 minute increments
+ // Must divide dijit._TimePicker.visibleIncrement evenly
+ clickableIncrement: "T00:15:00",
+
+ // visibleIncrement: String
+ // ISO-8601 string representing the amount by which
+ // every element with a visible time in the time picker increases.
+ // Set in local time, without a time zone.
+ // Example: `T01:00:00` creates text in every 1 hour increment
+ visibleIncrement: "T01:00:00",
+
+ // visibleRange: String
+ // ISO-8601 string representing the range of this TimePicker.
+ // The TimePicker will only display times in this range.
+ // Example: `T05:00:00` displays 5 hours of options
+ visibleRange: "T05:00:00",
+
+ // value: String
+ // Date to display.
+ // Defaults to current time and date.
+ // Can be a Date object or an ISO-8601 string.
+ // If you specify the GMT time zone (`-01:00`),
+ // the time will be converted to the local time in the local time zone.
+ // Otherwise, the time is considered to be in the local time zone.
+ // If you specify the date and isDate is true, the date is used.
+ // Example: if your local time zone is `GMT -05:00`,
+ // `T10:00:00` becomes `T10:00:00-05:00` (considered to be local time),
+ // `T10:00:00-01:00` becomes `T06:00:00-05:00` (4 hour difference),
+ // `T10:00:00Z` becomes `T05:00:00-05:00` (5 hour difference between Zulu and local time)
+ // `yyyy-mm-ddThh:mm:ss` is the format to set the date and time
+ // Example: `2007-06-01T09:00:00`
+ value: new Date(),
+
+ _visibleIncrement:2,
+ _clickableIncrement:1,
+ _totalIncrements:10,
+
+ // constraints: dijit._TimePicker.__Constraints
+ // Specifies valid range of times (start time, end time)
+ constraints:{},
+
+/*=====
+ serialize: function(val, options){
+ // summary:
+ // User overridable function used to convert the attr('value') result to a String
+ // val: Date
+ // The current value
+ // options: Object?
+ // tags:
+ // protected
+ },
+=====*/
+ serialize: dojo.date.stamp.toISOString,
+
+/*=====
+ // filterString: string
+ // The string to filter by
+ filterString: "",
+=====*/
+
+ setValue: function(/*Date*/ value){
+ // summary:
+ // Deprecated. Used set('value') instead.
+ // tags:
+ // deprecated
+ dojo.deprecated("dijit._TimePicker:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
+ this.set('value', value);
+ },
+
+ _setValueAttr: function(/*Date*/ date){
+ // summary:
+ // Hook so set('value', ...) works.
+ // description:
+ // Set the value of the TimePicker.
+ // Redraws the TimePicker around the new date.
+ // tags:
+ // protected
+ this._set("value", date);
+ this._showText();
+ },
+
+ _setFilterStringAttr: function(val){
+ // summary:
+ // Called by TimeTextBox to filter the values shown in my list
+ this._set("filterString", val);
+ this._showText();
+ },
+
+ isDisabledDate: function(/*Date*/ dateObject, /*String?*/ locale){
+ // summary:
+ // May be overridden to disable certain dates in the TimePicker e.g. `isDisabledDate=dojo.date.locale.isWeekend`
+ // type:
+ // extension
+ return false; // Boolean
+ },
+
+ _getFilteredNodes: function(/*number*/ start, /*number*/ maxNum, /*Boolean*/ before, /*DOMnode*/ lastNode){
+ // summary:
+ // Returns an array of nodes with the filter applied. At most maxNum nodes
+ // will be returned - but fewer may be returned as well. If the
+ // before parameter is set to true, then it will return the elements
+ // before the given index
+ // tags:
+ // private
+ var
+ nodes = [],
+ lastValue = lastNode ? lastNode.date : this._refDate,
+ n,
+ i = start,
+ max = this._maxIncrement + Math.abs(i),
+ chk = before ? -1 : 1,
+ dec = before ? 1 : 0,
+ inc = 1 - dec;
+ do{
+ i = i - dec;
+ n = this._createOption(i);
+ if(n){
+ if((before && n.date > lastValue) || (!before && n.date < lastValue)){
+ break; // don't wrap
+ }
+ nodes[before ? "unshift" : "push"](n);
+ lastValue = n.date;
+ }
+ i = i + inc;
+ }while(nodes.length < maxNum && (i*chk) < max);
+ return nodes;
+ },
+
+ _showText: function(){
+ // summary:
+ // Displays the relevant choices in the drop down list
+ // tags:
+ // private
+ var fromIso = dojo.date.stamp.fromISOString;
+ this.timeMenu.innerHTML = "";
+ this._clickableIncrementDate=fromIso(this.clickableIncrement);
+ this._visibleIncrementDate=fromIso(this.visibleIncrement);
+ this._visibleRangeDate=fromIso(this.visibleRange);
+ // get the value of the increments and the range in seconds (since 00:00:00) to find out how many divs to create
+ var
+ sinceMidnight = function(/*Date*/ date){
+ return date.getHours() * 60 * 60 + date.getMinutes() * 60 + date.getSeconds();
+ },
+ clickableIncrementSeconds = sinceMidnight(this._clickableIncrementDate),
+ visibleIncrementSeconds = sinceMidnight(this._visibleIncrementDate),
+ visibleRangeSeconds = sinceMidnight(this._visibleRangeDate),
+
+ // round reference date to previous visible increment
+ time = (this.value || this.currentFocus).getTime();
+
+ this._refDate = new Date(time - time % (visibleIncrementSeconds*1000));
+ this._refDate.setFullYear(1970,0,1); // match parse defaults
+
+ // assume clickable increment is the smallest unit
+ this._clickableIncrement = 1;
+ // divide the visible range by the clickable increment to get the number of divs to create
+ // example: 10:00:00/00:15:00 -> display 40 divs
+ this._totalIncrements = visibleRangeSeconds / clickableIncrementSeconds;
+ // divide the visible increments by the clickable increments to get how often to display the time inline
+ // example: 01:00:00/00:15:00 -> display the time every 4 divs
+ this._visibleIncrement = visibleIncrementSeconds / clickableIncrementSeconds;
+ // divide the number of seconds in a day by the clickable increment in seconds to get the
+ // absolute max number of increments.
+ this._maxIncrement = (60 * 60 * 24) / clickableIncrementSeconds;
+
+ var
+ // Find the nodes we should display based on our filter.
+ // Limit to 10 nodes displayed as a half-hearted attempt to stop drop down from overlapping <input>.
+ after = this._getFilteredNodes(0, Math.min(this._totalIncrements >> 1, 10) - 1),
+ before = this._getFilteredNodes(0, Math.min(this._totalIncrements, 10) - after.length, true, after[0]);
+ dojo.forEach(before.concat(after), function(n){this.timeMenu.appendChild(n);}, this);
+ },
+
+ constructor: function(){
+ this.constraints = {}; // create instance object
+ },
+
+ postMixInProperties: function(){
+ this.inherited(arguments);
+ this._setConstraintsAttr(this.constraints); // this needs to happen now (and later) due to codependency on _set*Attr calls
+ },
+
+ _setConstraintsAttr: function(/* Object */ constraints){
+ // brings in visibleRange, increments, etc.
+ dojo.mixin(this, constraints);
+
+ // dojo.date.locale needs the lang in the constraints as locale
+ if(!constraints.locale){
+ constraints.locale = this.lang;
+ }
+ },
+
+ postCreate: function(){
+ // assign typematic mouse listeners to the arrow buttons
+ this.connect(this.timeMenu, dojo.isIE ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled");
+ this._connects.push(dijit.typematic.addMouseListener(this.upArrow, this, "_onArrowUp", 33, 250));
+ this._connects.push(dijit.typematic.addMouseListener(this.downArrow, this, "_onArrowDown", 33, 250));
+
+ this.inherited(arguments);
+ },
+
+ _buttonMouse: function(/*Event*/ e){
+ // summary:
+ // Handler for hover (and unhover) on up/down arrows
+ // tags:
+ // private
+
+ // in non-IE browser the "mouseenter" event will become "mouseover",
+ // but in IE it's still "mouseenter"
+ dojo.toggleClass(e.currentTarget, e.currentTarget == this.upArrow ? "dijitUpArrowHover" : "dijitDownArrowHover",
+ e.type == "mouseenter" || e.type == "mouseover");
+ },
+
+ _createOption: function(/*Number*/ index){
+ // summary:
+ // Creates a clickable time option
+ // tags:
+ // private
+ var date = new Date(this._refDate);
+ var incrementDate = this._clickableIncrementDate;
+ date.setHours(date.getHours() + incrementDate.getHours() * index,
+ date.getMinutes() + incrementDate.getMinutes() * index,
+ date.getSeconds() + incrementDate.getSeconds() * index);
+ if(this.constraints.selector == "time"){
+ date.setFullYear(1970,0,1); // make sure each time is for the same date
+ }
+ var dateString = dojo.date.locale.format(date, this.constraints);
+ if(this.filterString && dateString.toLowerCase().indexOf(this.filterString) !== 0){
+ // Doesn't match the filter - return null
+ return null;
+ }
+
+ var div = dojo.create("div", {"class": this.baseClass+"Item"});
+ div.date = date;
+ div.index = index;
+ dojo.create('div',{
+ "class": this.baseClass + "ItemInner",
+ innerHTML: dateString
+ }, div);
+
+ if(index%this._visibleIncrement<1 && index%this._visibleIncrement>-1){
+ dojo.addClass(div, this.baseClass+"Marker");
+ }else if(!(index%this._clickableIncrement)){
+ dojo.addClass(div, this.baseClass+"Tick");
+ }
+
+ if(this.isDisabledDate(date)){
+ // set disabled
+ dojo.addClass(div, this.baseClass+"ItemDisabled");
+ }
+ if(this.value && !dojo.date.compare(this.value, date, this.constraints.selector)){
+ div.selected = true;
+ dojo.addClass(div, this.baseClass+"ItemSelected");
+ if(dojo.hasClass(div, this.baseClass+"Marker")){
+ dojo.addClass(div, this.baseClass+"MarkerSelected");
+ }else{
+ dojo.addClass(div, this.baseClass+"TickSelected");
+ }
+
+ // Initially highlight the current value. User can change highlight by up/down arrow keys
+ // or mouse movement.
+ this._highlightOption(div, true);
+ }
+ return div;
+ },
+
+ _onOptionSelected: function(/*Object*/ tgt){
+ // summary:
+ // Called when user clicks an option in the drop down list
+ // tags:
+ // private
+ var tdate = tgt.target.date || tgt.target.parentNode.date;
+ if(!tdate || this.isDisabledDate(tdate)){ return; }
+ this._highlighted_option = null;
+ this.set('value', tdate);
+ this.onChange(tdate);
+ },
+
+ onChange: function(/*Date*/ time){
+ // summary:
+ // Notification that a time was selected. It may be the same as the previous value.
+ // tags:
+ // public
+ },
+
+ _highlightOption: function(/*node*/ node, /*Boolean*/ highlight){
+ // summary:
+ // Turns on/off highlight effect on a node based on mouse out/over event
+ // tags:
+ // private
+ if(!node){return;}
+ if(highlight){
+ if(this._highlighted_option){
+ this._highlightOption(this._highlighted_option, false);
+ }
+ this._highlighted_option = node;
+ }else if(this._highlighted_option !== node){
+ return;
+ }else{
+ this._highlighted_option = null;
+ }
+ dojo.toggleClass(node, this.baseClass+"ItemHover", highlight);
+ if(dojo.hasClass(node, this.baseClass+"Marker")){
+ dojo.toggleClass(node, this.baseClass+"MarkerHover", highlight);
+ }else{
+ dojo.toggleClass(node, this.baseClass+"TickHover", highlight);
+ }
+ },
+
+ onmouseover: function(/*Event*/ e){
+ // summary:
+ // Handler for onmouseover event
+ // tags:
+ // private
+ this._keyboardSelected = null;
+ var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode;
+ // if we aren't targeting an item, then we return
+ if(!dojo.hasClass(tgr, this.baseClass+"Item")){return;}
+ this._highlightOption(tgr, true);
+ },
+
+ onmouseout: function(/*Event*/ e){
+ // summary:
+ // Handler for onmouseout event
+ // tags:
+ // private
+ this._keyboardSelected = null;
+ var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode;
+ this._highlightOption(tgr, false);
+ },
+
+ _mouseWheeled: function(/*Event*/ e){
+ // summary:
+ // Handle the mouse wheel events
+ // tags:
+ // private
+ this._keyboardSelected = null;
+ dojo.stopEvent(e);
+ // we're not _measuring_ the scroll amount, just direction
+ var scrollAmount = (dojo.isIE ? e.wheelDelta : -e.detail);
+ this[(scrollAmount>0 ? "_onArrowUp" : "_onArrowDown")](); // yes, we're making a new dom node every time you mousewheel, or click
+ },
+
+ _onArrowUp: function(count){
+ // summary:
+ // Handler for up arrow key.
+ // description:
+ // Removes the bottom time and add one to the top
+ // tags:
+ // private
+ if(typeof count == "number" && count == -1){ return; } // typematic end
+ if(!this.timeMenu.childNodes.length){ return; }
+ var index = this.timeMenu.childNodes[0].index;
+ var divs = this._getFilteredNodes(index, 1, true, this.timeMenu.childNodes[0]);
+ if(divs.length){
+ this.timeMenu.removeChild(this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1]);
+ this.timeMenu.insertBefore(divs[0], this.timeMenu.childNodes[0]);
+ }
+ },
+
+ _onArrowDown: function(count){
+ // summary:
+ // Handler for up arrow key.
+ // description:
+ // Remove the top time and add one to the bottom
+ // tags:
+ // private
+ if(typeof count == "number" && count == -1){ return; } // typematic end
+ if(!this.timeMenu.childNodes.length){ return; }
+ var index = this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1].index + 1;
+ var divs = this._getFilteredNodes(index, 1, false, this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1]);
+ if(divs.length){
+ this.timeMenu.removeChild(this.timeMenu.childNodes[0]);
+ this.timeMenu.appendChild(divs[0]);
+ }
+ },
+
+ handleKey: function(/*Event*/ e){
+ // summary:
+ // Called from `dijit.form._DateTimeTextBox` to pass a keypress event
+ // from the `dijit.form.TimeTextBox` to be handled in this widget
+ // tags:
+ // protected
+ var dk = dojo.keys;
+ if(e.charOrCode == dk.DOWN_ARROW || e.charOrCode == dk.UP_ARROW){
+ dojo.stopEvent(e);
+ // Figure out which option to highlight now and then highlight it
+ if(this._highlighted_option && !this._highlighted_option.parentNode){
+ this._highlighted_option = null;
+ }
+ var timeMenu = this.timeMenu,
+ tgt = this._highlighted_option || dojo.query("." + this.baseClass + "ItemSelected", timeMenu)[0];
+ if(!tgt){
+ tgt = timeMenu.childNodes[0];
+ }else if(timeMenu.childNodes.length){
+ if(e.charOrCode == dk.DOWN_ARROW && !tgt.nextSibling){
+ this._onArrowDown();
+ }else if(e.charOrCode == dk.UP_ARROW && !tgt.previousSibling){
+ this._onArrowUp();
+ }
+ if(e.charOrCode == dk.DOWN_ARROW){
+ tgt = tgt.nextSibling;
+ }else{
+ tgt = tgt.previousSibling;
+ }
+ }
+ this._highlightOption(tgt, true);
+ this._keyboardSelected = tgt;
+ return false;
+ }else if(e.charOrCode == dk.ENTER || e.charOrCode === dk.TAB){
+ // mouse hover followed by TAB is NO selection
+ if(!this._keyboardSelected && e.charOrCode === dk.TAB){
+ return true; // true means don't call stopEvent()
+ }
+
+ // Accept the currently-highlighted option as the value
+ if(this._highlighted_option){
+ this._onOptionSelected({target: this._highlighted_option});
+ }
+
+ // Call stopEvent() for ENTER key so that form doesn't submit,
+ // but not for TAB, so that TAB does switch focus
+ return e.charOrCode === dk.TAB;
+ }
+ }
+ }
+);
+
}