2 'url:dijit/templates/TimePicker.html':"<div id=\"widget_${id}\" class=\"dijitMenu\"\n ><div data-dojo-attach-point=\"upArrow\" class=\"dijitButtonNode dijitUpArrowButton\" data-dojo-attach-event=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" role=\"presentation\"> </div\n\t\t><div class=\"dijitArrowButtonChar\">▲</div></div\n ><div data-dojo-attach-point=\"timeMenu,focusNode\" data-dojo-attach-event=\"onclick:_onOptionSelected,onmouseover,onmouseout\"></div\n ><div data-dojo-attach-point=\"downArrow\" class=\"dijitButtonNode dijitDownArrowButton\" data-dojo-attach-event=\"onmouseenter:_buttonMouse,onmouseleave:_buttonMouse\"\n\t\t><div class=\"dijitReset dijitInline dijitArrowButtonInner\" role=\"presentation\"> </div\n\t\t><div class=\"dijitArrowButtonChar\">▼</div></div\n></div>\n"}});
3 define("dijit/_TimePicker", [
4 "dojo/_base/array", // array.forEach
5 "dojo/date", // date.compare
6 "dojo/date/locale", // locale.format
7 "dojo/date/stamp", // stamp.fromISOString stamp.toISOString
8 "dojo/_base/declare", // declare
9 "dojo/dom-class", // domClass.add domClass.contains domClass.toggle
10 "dojo/dom-construct", // domConstruct.create
11 "dojo/_base/event", // event.stop
12 "dojo/_base/kernel", // deprecated
14 "dojo/_base/lang", // lang.mixin
15 "dojo/sniff", // has(...)
16 "dojo/query", // query
17 "dojo/mouse", // mouse.wheel
21 "./form/_FormValueWidget",
22 "dojo/text!./templates/TimePicker.html"
23 ], function(array
, ddate
, locale
, stamp
, declare
, domClass
, domConstruct
, event
, kernel
, keys
, lang
, has
, query
, mouse
,
24 typematic
, _Widget
, _TemplatedMixin
, _FormValueWidget
, template
){
30 var TimePicker
= declare("dijit._TimePicker", [_Widget
, _TemplatedMixin
], {
32 // A graphical time picker.
33 // This widget is used internally by other widgets and is not available
34 // as a standalone widget due to lack of accessibility support.
36 templateString
: template
,
38 // baseClass: [protected] String
39 // The root className to use for the various states of this widget
40 baseClass
: "dijitTimePicker",
42 // clickableIncrement: String
43 // ISO-8601 string representing the amount by which
44 // every clickable element in the time picker increases.
45 // Set in local time, without a time zone.
46 // Example: `T00:15:00` creates 15 minute increments
47 // Must divide dijit/_TimePicker.visibleIncrement evenly
48 clickableIncrement
: "T00:15:00",
50 // visibleIncrement: String
51 // ISO-8601 string representing the amount by which
52 // every element with a visible time in the time picker increases.
53 // Set in local time, without a time zone.
54 // Example: `T01:00:00` creates text in every 1 hour increment
55 visibleIncrement
: "T01:00:00",
57 // visibleRange: String
58 // ISO-8601 string representing the range of this TimePicker.
59 // The TimePicker will only display times in this range.
60 // Example: `T05:00:00` displays 5 hours of options
61 visibleRange
: "T05:00:00",
65 // Defaults to current time and date.
66 // Can be a Date object or an ISO-8601 string.
67 // If you specify the GMT time zone (`-01:00`),
68 // the time will be converted to the local time in the local time zone.
69 // Otherwise, the time is considered to be in the local time zone.
70 // If you specify the date and isDate is true, the date is used.
71 // Example: if your local time zone is `GMT -05:00`,
72 // `T10:00:00` becomes `T10:00:00-05:00` (considered to be local time),
73 // `T10:00:00-01:00` becomes `T06:00:00-05:00` (4 hour difference),
74 // `T10:00:00Z` becomes `T05:00:00-05:00` (5 hour difference between Zulu and local time)
75 // `yyyy-mm-ddThh:mm:ss` is the format to set the date and time
76 // Example: `2007-06-01T09:00:00`
80 _clickableIncrement
:1,
83 // constraints: TimePicker.__Constraints
84 // Specifies valid range of times (start time, end time)
88 serialize: function(val, options){
90 // User overridable function used to convert the attr('value') result to a String
98 serialize
: stamp
.toISOString
,
101 // filterString: string
102 // The string to filter by
106 setValue: function(/*Date*/ value
){
108 // Deprecated. Used set('value') instead.
111 kernel
.deprecated("dijit._TimePicker:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
112 this.set('value', value
);
115 _setValueAttr: function(/*Date*/ date
){
117 // Hook so set('value', ...) works.
119 // Set the value of the TimePicker.
120 // Redraws the TimePicker around the new date.
123 this._set("value", date
);
127 _setFilterStringAttr: function(val
){
129 // Called by TimeTextBox to filter the values shown in my list
130 this._set("filterString", val
);
134 isDisabledDate: function(/*===== dateObject, locale =====*/){
136 // May be overridden to disable certain dates in the TimePicker e.g. `isDisabledDate=locale.isWeekend`
141 return false; // Boolean
144 _getFilteredNodes: function(/*number*/ start
, /*number*/ maxNum
, /*Boolean*/ before
, /*DOMnode*/ lastNode
){
146 // Returns an array of nodes with the filter applied. At most maxNum nodes
147 // will be returned - but fewer may be returned as well. If the
148 // before parameter is set to true, then it will return the elements
149 // before the given index
154 lastValue
= lastNode
? lastNode
.date
: this._refDate
,
157 max
= this._maxIncrement
+ Math
.abs(i
),
158 chk
= before
? -1 : 1,
159 dec
= before
? 1 : 0,
163 n
= this._createOption(i
);
165 if((before
&& n
.date
> lastValue
) || (!before
&& n
.date
< lastValue
)){
168 nodes
[before
? "unshift" : "push"](n
);
172 }while(nodes
.length
< maxNum
&& (i
*chk
) < max
);
176 _showText: function(){
178 // Displays the relevant choices in the drop down list
181 var fromIso
= stamp
.fromISOString
;
182 this.timeMenu
.innerHTML
= "";
183 this._clickableIncrementDate
=fromIso(this.clickableIncrement
);
184 this._visibleIncrementDate
=fromIso(this.visibleIncrement
);
185 this._visibleRangeDate
=fromIso(this.visibleRange
);
186 // get the value of the increments and the range in seconds (since 00:00:00) to find out how many divs to create
188 sinceMidnight = function(/*Date*/ date
){
189 return date
.getHours() * 60 * 60 + date
.getMinutes() * 60 + date
.getSeconds();
191 clickableIncrementSeconds
= sinceMidnight(this._clickableIncrementDate
),
192 visibleIncrementSeconds
= sinceMidnight(this._visibleIncrementDate
),
193 visibleRangeSeconds
= sinceMidnight(this._visibleRangeDate
),
194 // round reference date to previous visible increment
195 time
= (this.value
|| this.currentFocus
).getTime();
197 this._refDate
= new Date(time
- time
% (clickableIncrementSeconds
*1000));
198 this._refDate
.setFullYear(1970,0,1); // match parse defaults
200 // assume clickable increment is the smallest unit
201 this._clickableIncrement
= 1;
202 // divide the visible range by the clickable increment to get the number of divs to create
203 // example: 10:00:00/00:15:00 -> display 40 divs
204 this._totalIncrements
= visibleRangeSeconds
/ clickableIncrementSeconds
;
205 // divide the visible increments by the clickable increments to get how often to display the time inline
206 // example: 01:00:00/00:15:00 -> display the time every 4 divs
207 this._visibleIncrement
= visibleIncrementSeconds
/ clickableIncrementSeconds
;
208 // divide the number of seconds in a day by the clickable increment in seconds to get the
209 // absolute max number of increments.
210 this._maxIncrement
= (60 * 60 * 24) / clickableIncrementSeconds
;
213 // Find the nodes we should display based on our filter.
214 // Limit to 10 nodes displayed as a half-hearted attempt to stop drop down from overlapping <input>.
215 count
= Math
.min(this._totalIncrements
, 10),
216 after
= this._getFilteredNodes(0, (count
>> 1) + 1, false),
218 estBeforeLength
= count
- after
.length
,
219 before
= this._getFilteredNodes(0, estBeforeLength
, true, after
[0]);
220 if(before
.length
< estBeforeLength
&& after
.length
> 0){
221 moreAfter
= this._getFilteredNodes(after
[after
.length
-1].idx
+ 1, estBeforeLength
- before
.length
, false, after
[after
.length
-1]);
223 array
.forEach(before
.concat(after
, moreAfter
), function(n
){ this.timeMenu
.appendChild(n
); }, this);
224 // never show empty due to a bad filter
225 if(!before
.length
&& !after
.length
&& !moreAfter
.length
&& this.filterString
){
226 this.filterString
= '';
231 constructor: function(/*===== params, srcNodeRef =====*/){
233 // Create the widget.
234 // params: Object|null
235 // Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
236 // and functions, typically callbacks like onClick.
237 // The hash can contain any of the widget's properties, excluding read-only properties.
238 // srcNodeRef: DOMNode|String?
239 // If a srcNodeRef (DOM node) is specified, replace srcNodeRef with my generated DOM tree
241 this.constraints
= {};
244 postMixInProperties: function(){
245 this.inherited(arguments
);
246 this._setConstraintsAttr(this.constraints
); // this needs to happen now (and later) due to codependency on _set*Attr calls
249 _setConstraintsAttr: function(/* Object */ constraints
){
250 // brings in visibleRange, increments, etc.
251 lang
.mixin(this, constraints
);
253 // locale needs the lang in the constraints as locale
254 if(!constraints
.locale
){
255 constraints
.locale
= this.lang
;
259 postCreate: function(){
260 // assign typematic mouse listeners to the arrow buttons
261 this.connect(this.timeMenu
, mouse
.wheel
, "_mouseWheeled");
263 typematic
.addMouseListener(this.upArrow
, this, "_onArrowUp", 33, 250),
264 typematic
.addMouseListener(this.downArrow
, this, "_onArrowDown", 33, 250)
267 this.inherited(arguments
);
270 _buttonMouse: function(/*Event*/ e
){
272 // Handler for hover (and unhover) on up/down arrows
276 // in non-IE browser the "mouseenter" event will become "mouseover",
277 // but in IE it's still "mouseenter"
278 domClass
.toggle(e
.currentTarget
, e
.currentTarget
== this.upArrow
? "dijitUpArrowHover" : "dijitDownArrowHover",
279 e
.type
== "mouseenter" || e
.type
== "mouseover");
282 _createOption: function(/*Number*/ index
){
284 // Creates a clickable time option
287 var date
= new Date(this._refDate
);
288 var incrementDate
= this._clickableIncrementDate
;
289 date
.setTime(date
.getTime()
290 + incrementDate
.getHours() * index
* 3600000
291 + incrementDate
.getMinutes() * index
* 60000
292 + incrementDate
.getSeconds() * index
* 1000);
293 if(this.constraints
.selector
== "time"){
294 date
.setFullYear(1970,0,1); // make sure each time is for the same date
296 var dateString
= locale
.format(date
, this.constraints
);
297 if(this.filterString
&& dateString
.toLowerCase().indexOf(this.filterString
) !== 0){
298 // Doesn't match the filter - return null
302 var div
= this.ownerDocument
.createElement("div");
303 div
.className
= this.baseClass
+"Item";
306 domConstruct
.create('div',{
307 "class": this.baseClass
+ "ItemInner",
308 innerHTML
: dateString
311 if(index
%this._visibleIncrement
<1 && index
%this._visibleIncrement
>-1){
312 domClass
.add(div
, this.baseClass
+"Marker");
313 }else if(!(index
%this._clickableIncrement
)){
314 domClass
.add(div
, this.baseClass
+"Tick");
317 if(this.isDisabledDate(date
)){
319 domClass
.add(div
, this.baseClass
+"ItemDisabled");
321 if(this.value
&& !ddate
.compare(this.value
, date
, this.constraints
.selector
)){
323 domClass
.add(div
, this.baseClass
+"ItemSelected");
324 if(domClass
.contains(div
, this.baseClass
+"Marker")){
325 domClass
.add(div
, this.baseClass
+"MarkerSelected");
327 domClass
.add(div
, this.baseClass
+"TickSelected");
330 // Initially highlight the current value. User can change highlight by up/down arrow keys
331 // or mouse movement.
332 this._highlightOption(div
, true);
337 _onOptionSelected: function(/*Object*/ tgt
){
339 // Called when user clicks an option in the drop down list
342 var tdate
= tgt
.target
.date
|| tgt
.target
.parentNode
.date
;
343 if(!tdate
|| this.isDisabledDate(tdate
)){ return; }
344 this._highlighted_option
= null;
345 this.set('value', tdate
);
346 this.onChange(tdate
);
349 onChange: function(/*Date*/ /*===== time =====*/){
351 // Notification that a time was selected. It may be the same as the previous value.
356 _highlightOption: function(/*node*/ node
, /*Boolean*/ highlight
){
358 // Turns on/off highlight effect on a node based on mouse out/over event
363 if(this._highlighted_option
){
364 this._highlightOption(this._highlighted_option
, false);
366 this._highlighted_option
= node
;
367 }else if(this._highlighted_option
!== node
){
370 this._highlighted_option
= null;
372 domClass
.toggle(node
, this.baseClass
+"ItemHover", highlight
);
373 if(domClass
.contains(node
, this.baseClass
+"Marker")){
374 domClass
.toggle(node
, this.baseClass
+"MarkerHover", highlight
);
376 domClass
.toggle(node
, this.baseClass
+"TickHover", highlight
);
380 onmouseover: function(/*Event*/ e
){
382 // Handler for onmouseover event
385 this._keyboardSelected
= null;
386 var tgr
= (e
.target
.parentNode
=== this.timeMenu
) ? e
.target
: e
.target
.parentNode
;
387 // if we aren't targeting an item, then we return
388 if(!domClass
.contains(tgr
, this.baseClass
+"Item")){return;}
389 this._highlightOption(tgr
, true);
392 onmouseout: function(/*Event*/ e
){
394 // Handler for onmouseout event
397 this._keyboardSelected
= null;
398 var tgr
= (e
.target
.parentNode
=== this.timeMenu
) ? e
.target
: e
.target
.parentNode
;
399 this._highlightOption(tgr
, false);
402 _mouseWheeled: function(/*Event*/ e
){
404 // Handle the mouse wheel events
407 this._keyboardSelected
= null;
409 // we're not _measuring_ the scroll amount, just direction
410 this[(e
.wheelDelta
>0 ? "_onArrowUp" : "_onArrowDown")](); // yes, we're making a new dom node every time you mousewheel, or click
413 _onArrowUp: function(count
){
415 // Handler for up arrow key.
417 // Removes the bottom time and add one to the top
421 domClass
.remove(this.upArrow
, "dijitUpArrowActive");
423 }else if(count
=== 0){
424 domClass
.add(this.upArrow
, "dijitUpArrowActive");
427 if(!this.timeMenu
.childNodes
.length
){ return; }
428 var index
= this.timeMenu
.childNodes
[0].idx
;
429 var divs
= this._getFilteredNodes(index
, 1, true, this.timeMenu
.childNodes
[0]);
431 this.timeMenu
.removeChild(this.timeMenu
.childNodes
[this.timeMenu
.childNodes
.length
- 1]);
432 this.timeMenu
.insertBefore(divs
[0], this.timeMenu
.childNodes
[0]);
436 _onArrowDown: function(count
){
438 // Handler for up arrow key.
440 // Remove the top time and add one to the bottom
444 domClass
.remove(this.downArrow
, "dijitDownArrowActive");
446 }else if(count
=== 0){
447 domClass
.add(this.downArrow
, "dijitDownArrowActive");
449 if(!this.timeMenu
.childNodes
.length
){ return; }
450 var index
= this.timeMenu
.childNodes
[this.timeMenu
.childNodes
.length
- 1].idx
+ 1;
451 var divs
= this._getFilteredNodes(index
, 1, false, this.timeMenu
.childNodes
[this.timeMenu
.childNodes
.length
- 1]);
453 this.timeMenu
.removeChild(this.timeMenu
.childNodes
[0]);
454 this.timeMenu
.appendChild(divs
[0]);
458 handleKey: function(/*Event*/ e
){
460 // Called from `dijit/form/_DateTimeTextBox` to pass a keypress event
461 // from the `dijit/form/TimeTextBox` to be handled in this widget
464 if(e
.keyCode
== keys
.DOWN_ARROW
|| e
.keyCode
== keys
.UP_ARROW
){
466 // Figure out which option to highlight now and then highlight it
467 if(this._highlighted_option
&& !this._highlighted_option
.parentNode
){
468 this._highlighted_option
= null;
470 var timeMenu
= this.timeMenu
,
471 tgt
= this._highlighted_option
|| query("." + this.baseClass
+ "ItemSelected", timeMenu
)[0];
473 tgt
= timeMenu
.childNodes
[0];
474 }else if(timeMenu
.childNodes
.length
){
475 if(e
.keyCode
== keys
.DOWN_ARROW
&& !tgt
.nextSibling
){
477 }else if(e
.keyCode
== keys
.UP_ARROW
&& !tgt
.previousSibling
){
480 if(e
.keyCode
== keys
.DOWN_ARROW
){
481 tgt
= tgt
.nextSibling
;
483 tgt
= tgt
.previousSibling
;
486 this._highlightOption(tgt
, true);
487 this._keyboardSelected
= tgt
;
489 }else if(e
.keyCode
== keys
.ENTER
|| e
.keyCode
=== keys
.TAB
){
490 // mouse hover followed by TAB is NO selection
491 if(!this._keyboardSelected
&& e
.keyCode
=== keys
.TAB
){
492 return true; // true means don't call stopEvent()
495 // Accept the currently-highlighted option as the value
496 if(this._highlighted_option
){
497 this._onOptionSelected({target
: this._highlighted_option
});
500 // Call stopEvent() for ENTER key so that form doesn't submit,
501 // but not for TAB, so that TAB does switch focus
502 return e
.keyCode
=== keys
.TAB
;
509 TimePicker.__Constraints = declare(locale.__FormatOptions, {
510 // clickableIncrement: String
511 // See `dijit/_TimePicker.clickableIncrement`
512 clickableIncrement: "T00:15:00",
514 // visibleIncrement: String
515 // See `dijit/_TimePicker.visibleIncrement`
516 visibleIncrement: "T01:00:00",
518 // visibleRange: String
519 // See `dijit/_TimePicker.visibleRange`
520 visibleRange: "T05:00:00"