1 | define([ |
---|
2 | "dojo/_base/array", // array.forEach |
---|
3 | "dojo/date", // date.compare |
---|
4 | "dojo/date/locale", // locale.format |
---|
5 | "dojo/date/stamp", // stamp.fromISOString stamp.toISOString |
---|
6 | "dojo/_base/declare", // declare |
---|
7 | "dojo/dom-class", // domClass.add domClass.contains domClass.toggle |
---|
8 | "dojo/dom-construct", // domConstruct.create |
---|
9 | "dojo/_base/event", // event.stop |
---|
10 | "dojo/_base/kernel", // deprecated |
---|
11 | "dojo/keys", // keys |
---|
12 | "dojo/_base/lang", // lang.mixin |
---|
13 | "dojo/_base/sniff", // has("ie") |
---|
14 | "dojo/query", // query |
---|
15 | "dijit/typematic", |
---|
16 | "./_Widget", |
---|
17 | "./_TemplatedMixin", |
---|
18 | "./form/_FormValueWidget", |
---|
19 | "dojo/text!./templates/TimePicker.html" |
---|
20 | ], function(array, ddate, locale, stamp, declare, domClass, domConstruct, event, kernel, keys, lang, has, query, |
---|
21 | typematic, _Widget, _TemplatedMixin, _FormValueWidget, template){ |
---|
22 | |
---|
23 | /*===== |
---|
24 | var _Widget = dijit._Widget; |
---|
25 | var _TemplatedMixin = dijit._TemplatedMixin; |
---|
26 | var _FormValueWidget = dijit.form._FormValueWidget; |
---|
27 | =====*/ |
---|
28 | |
---|
29 | // module: |
---|
30 | // dijit/_TimePicker |
---|
31 | // summary: |
---|
32 | // A graphical time picker. |
---|
33 | |
---|
34 | |
---|
35 | /*===== |
---|
36 | declare( |
---|
37 | "dijit._TimePicker.__Constraints", |
---|
38 | locale.__FormatOptions, |
---|
39 | { |
---|
40 | // clickableIncrement: String |
---|
41 | // See `dijit._TimePicker.clickableIncrement` |
---|
42 | clickableIncrement: "T00:15:00", |
---|
43 | |
---|
44 | // visibleIncrement: String |
---|
45 | // See `dijit._TimePicker.visibleIncrement` |
---|
46 | visibleIncrement: "T01:00:00", |
---|
47 | |
---|
48 | // visibleRange: String |
---|
49 | // See `dijit._TimePicker.visibleRange` |
---|
50 | visibleRange: "T05:00:00" |
---|
51 | } |
---|
52 | ); |
---|
53 | =====*/ |
---|
54 | |
---|
55 | return declare("dijit._TimePicker", [_Widget, _TemplatedMixin], { |
---|
56 | // summary: |
---|
57 | // A graphical time picker. |
---|
58 | // This widget is used internally by other widgets and is not available |
---|
59 | // as a standalone widget due to lack of accessibility support. |
---|
60 | |
---|
61 | templateString: template, |
---|
62 | |
---|
63 | // baseClass: [protected] String |
---|
64 | // The root className to use for the various states of this widget |
---|
65 | baseClass: "dijitTimePicker", |
---|
66 | |
---|
67 | // clickableIncrement: String |
---|
68 | // ISO-8601 string representing the amount by which |
---|
69 | // every clickable element in the time picker increases. |
---|
70 | // Set in local time, without a time zone. |
---|
71 | // Example: `T00:15:00` creates 15 minute increments |
---|
72 | // Must divide dijit._TimePicker.visibleIncrement evenly |
---|
73 | clickableIncrement: "T00:15:00", |
---|
74 | |
---|
75 | // visibleIncrement: String |
---|
76 | // ISO-8601 string representing the amount by which |
---|
77 | // every element with a visible time in the time picker increases. |
---|
78 | // Set in local time, without a time zone. |
---|
79 | // Example: `T01:00:00` creates text in every 1 hour increment |
---|
80 | visibleIncrement: "T01:00:00", |
---|
81 | |
---|
82 | // visibleRange: String |
---|
83 | // ISO-8601 string representing the range of this TimePicker. |
---|
84 | // The TimePicker will only display times in this range. |
---|
85 | // Example: `T05:00:00` displays 5 hours of options |
---|
86 | visibleRange: "T05:00:00", |
---|
87 | |
---|
88 | // value: String |
---|
89 | // Date to display. |
---|
90 | // Defaults to current time and date. |
---|
91 | // Can be a Date object or an ISO-8601 string. |
---|
92 | // If you specify the GMT time zone (`-01:00`), |
---|
93 | // the time will be converted to the local time in the local time zone. |
---|
94 | // Otherwise, the time is considered to be in the local time zone. |
---|
95 | // If you specify the date and isDate is true, the date is used. |
---|
96 | // Example: if your local time zone is `GMT -05:00`, |
---|
97 | // `T10:00:00` becomes `T10:00:00-05:00` (considered to be local time), |
---|
98 | // `T10:00:00-01:00` becomes `T06:00:00-05:00` (4 hour difference), |
---|
99 | // `T10:00:00Z` becomes `T05:00:00-05:00` (5 hour difference between Zulu and local time) |
---|
100 | // `yyyy-mm-ddThh:mm:ss` is the format to set the date and time |
---|
101 | // Example: `2007-06-01T09:00:00` |
---|
102 | value: new Date(), |
---|
103 | |
---|
104 | _visibleIncrement:2, |
---|
105 | _clickableIncrement:1, |
---|
106 | _totalIncrements:10, |
---|
107 | |
---|
108 | // constraints: dijit._TimePicker.__Constraints |
---|
109 | // Specifies valid range of times (start time, end time) |
---|
110 | constraints:{}, |
---|
111 | |
---|
112 | /*===== |
---|
113 | serialize: function(val, options){ |
---|
114 | // summary: |
---|
115 | // User overridable function used to convert the attr('value') result to a String |
---|
116 | // val: Date |
---|
117 | // The current value |
---|
118 | // options: Object? |
---|
119 | // tags: |
---|
120 | // protected |
---|
121 | }, |
---|
122 | =====*/ |
---|
123 | serialize: stamp.toISOString, |
---|
124 | |
---|
125 | /*===== |
---|
126 | // filterString: string |
---|
127 | // The string to filter by |
---|
128 | filterString: "", |
---|
129 | =====*/ |
---|
130 | |
---|
131 | setValue: function(/*Date*/ value){ |
---|
132 | // summary: |
---|
133 | // Deprecated. Used set('value') instead. |
---|
134 | // tags: |
---|
135 | // deprecated |
---|
136 | kernel.deprecated("dijit._TimePicker:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0"); |
---|
137 | this.set('value', value); |
---|
138 | }, |
---|
139 | |
---|
140 | _setValueAttr: function(/*Date*/ date){ |
---|
141 | // summary: |
---|
142 | // Hook so set('value', ...) works. |
---|
143 | // description: |
---|
144 | // Set the value of the TimePicker. |
---|
145 | // Redraws the TimePicker around the new date. |
---|
146 | // tags: |
---|
147 | // protected |
---|
148 | this._set("value", date); |
---|
149 | this._showText(); |
---|
150 | }, |
---|
151 | |
---|
152 | _setFilterStringAttr: function(val){ |
---|
153 | // summary: |
---|
154 | // Called by TimeTextBox to filter the values shown in my list |
---|
155 | this._set("filterString", val); |
---|
156 | this._showText(); |
---|
157 | }, |
---|
158 | |
---|
159 | isDisabledDate: function(/*===== dateObject, locale =====*/){ |
---|
160 | // summary: |
---|
161 | // May be overridden to disable certain dates in the TimePicker e.g. `isDisabledDate=locale.isWeekend` |
---|
162 | // dateObject: Date |
---|
163 | // locale: String? |
---|
164 | // type: |
---|
165 | // extension |
---|
166 | return false; // Boolean |
---|
167 | }, |
---|
168 | |
---|
169 | _getFilteredNodes: function(/*number*/ start, /*number*/ maxNum, /*Boolean*/ before, /*DOMnode*/ lastNode){ |
---|
170 | // summary: |
---|
171 | // Returns an array of nodes with the filter applied. At most maxNum nodes |
---|
172 | // will be returned - but fewer may be returned as well. If the |
---|
173 | // before parameter is set to true, then it will return the elements |
---|
174 | // before the given index |
---|
175 | // tags: |
---|
176 | // private |
---|
177 | var |
---|
178 | nodes = [], |
---|
179 | lastValue = lastNode ? lastNode.date : this._refDate, |
---|
180 | n, |
---|
181 | i = start, |
---|
182 | max = this._maxIncrement + Math.abs(i), |
---|
183 | chk = before ? -1 : 1, |
---|
184 | dec = before ? 1 : 0, |
---|
185 | inc = 1 - dec; |
---|
186 | do{ |
---|
187 | i = i - dec; |
---|
188 | n = this._createOption(i); |
---|
189 | if(n){ |
---|
190 | if((before && n.date > lastValue) || (!before && n.date < lastValue)){ |
---|
191 | break; // don't wrap |
---|
192 | } |
---|
193 | nodes[before ? "unshift" : "push"](n); |
---|
194 | lastValue = n.date; |
---|
195 | } |
---|
196 | i = i + inc; |
---|
197 | }while(nodes.length < maxNum && (i*chk) < max); |
---|
198 | return nodes; |
---|
199 | }, |
---|
200 | |
---|
201 | _showText: function(){ |
---|
202 | // summary: |
---|
203 | // Displays the relevant choices in the drop down list |
---|
204 | // tags: |
---|
205 | // private |
---|
206 | var fromIso = stamp.fromISOString; |
---|
207 | this.timeMenu.innerHTML = ""; |
---|
208 | this._clickableIncrementDate=fromIso(this.clickableIncrement); |
---|
209 | this._visibleIncrementDate=fromIso(this.visibleIncrement); |
---|
210 | this._visibleRangeDate=fromIso(this.visibleRange); |
---|
211 | // get the value of the increments and the range in seconds (since 00:00:00) to find out how many divs to create |
---|
212 | var |
---|
213 | sinceMidnight = function(/*Date*/ date){ |
---|
214 | return date.getHours() * 60 * 60 + date.getMinutes() * 60 + date.getSeconds(); |
---|
215 | }, |
---|
216 | clickableIncrementSeconds = sinceMidnight(this._clickableIncrementDate), |
---|
217 | visibleIncrementSeconds = sinceMidnight(this._visibleIncrementDate), |
---|
218 | visibleRangeSeconds = sinceMidnight(this._visibleRangeDate), |
---|
219 | |
---|
220 | // round reference date to previous visible increment |
---|
221 | time = (this.value || this.currentFocus).getTime(); |
---|
222 | |
---|
223 | this._refDate = new Date(time - time % (visibleIncrementSeconds*1000)); |
---|
224 | this._refDate.setFullYear(1970,0,1); // match parse defaults |
---|
225 | |
---|
226 | // assume clickable increment is the smallest unit |
---|
227 | this._clickableIncrement = 1; |
---|
228 | // divide the visible range by the clickable increment to get the number of divs to create |
---|
229 | // example: 10:00:00/00:15:00 -> display 40 divs |
---|
230 | this._totalIncrements = visibleRangeSeconds / clickableIncrementSeconds; |
---|
231 | // divide the visible increments by the clickable increments to get how often to display the time inline |
---|
232 | // example: 01:00:00/00:15:00 -> display the time every 4 divs |
---|
233 | this._visibleIncrement = visibleIncrementSeconds / clickableIncrementSeconds; |
---|
234 | // divide the number of seconds in a day by the clickable increment in seconds to get the |
---|
235 | // absolute max number of increments. |
---|
236 | this._maxIncrement = (60 * 60 * 24) / clickableIncrementSeconds; |
---|
237 | |
---|
238 | var |
---|
239 | // Find the nodes we should display based on our filter. |
---|
240 | // Limit to 10 nodes displayed as a half-hearted attempt to stop drop down from overlapping <input>. |
---|
241 | after = this._getFilteredNodes(0, Math.min(this._totalIncrements >> 1, 10) - 1), |
---|
242 | before = this._getFilteredNodes(0, Math.min(this._totalIncrements, 10) - after.length, true, after[0]); |
---|
243 | array.forEach(before.concat(after), function(n){this.timeMenu.appendChild(n);}, this); |
---|
244 | }, |
---|
245 | |
---|
246 | constructor: function(){ |
---|
247 | this.constraints = {}; // create instance object |
---|
248 | }, |
---|
249 | |
---|
250 | postMixInProperties: function(){ |
---|
251 | this.inherited(arguments); |
---|
252 | this._setConstraintsAttr(this.constraints); // this needs to happen now (and later) due to codependency on _set*Attr calls |
---|
253 | }, |
---|
254 | |
---|
255 | _setConstraintsAttr: function(/* Object */ constraints){ |
---|
256 | // brings in visibleRange, increments, etc. |
---|
257 | lang.mixin(this, constraints); |
---|
258 | |
---|
259 | // locale needs the lang in the constraints as locale |
---|
260 | if(!constraints.locale){ |
---|
261 | constraints.locale = this.lang; |
---|
262 | } |
---|
263 | }, |
---|
264 | |
---|
265 | postCreate: function(){ |
---|
266 | // assign typematic mouse listeners to the arrow buttons |
---|
267 | this.connect(this.timeMenu, has("ie") ? "onmousewheel" : 'DOMMouseScroll', "_mouseWheeled"); |
---|
268 | this._connects.push(typematic.addMouseListener(this.upArrow, this, "_onArrowUp", 33, 250)); |
---|
269 | this._connects.push(typematic.addMouseListener(this.downArrow, this, "_onArrowDown", 33, 250)); |
---|
270 | |
---|
271 | this.inherited(arguments); |
---|
272 | }, |
---|
273 | |
---|
274 | _buttonMouse: function(/*Event*/ e){ |
---|
275 | // summary: |
---|
276 | // Handler for hover (and unhover) on up/down arrows |
---|
277 | // tags: |
---|
278 | // private |
---|
279 | |
---|
280 | // in non-IE browser the "mouseenter" event will become "mouseover", |
---|
281 | // but in IE it's still "mouseenter" |
---|
282 | domClass.toggle(e.currentTarget, e.currentTarget == this.upArrow ? "dijitUpArrowHover" : "dijitDownArrowHover", |
---|
283 | e.type == "mouseenter" || e.type == "mouseover"); |
---|
284 | }, |
---|
285 | |
---|
286 | _createOption: function(/*Number*/ index){ |
---|
287 | // summary: |
---|
288 | // Creates a clickable time option |
---|
289 | // tags: |
---|
290 | // private |
---|
291 | var date = new Date(this._refDate); |
---|
292 | var incrementDate = this._clickableIncrementDate; |
---|
293 | date.setHours(date.getHours() + incrementDate.getHours() * index, |
---|
294 | date.getMinutes() + incrementDate.getMinutes() * index, |
---|
295 | date.getSeconds() + incrementDate.getSeconds() * index); |
---|
296 | if(this.constraints.selector == "time"){ |
---|
297 | date.setFullYear(1970,0,1); // make sure each time is for the same date |
---|
298 | } |
---|
299 | var dateString = locale.format(date, this.constraints); |
---|
300 | if(this.filterString && dateString.toLowerCase().indexOf(this.filterString) !== 0){ |
---|
301 | // Doesn't match the filter - return null |
---|
302 | return null; |
---|
303 | } |
---|
304 | |
---|
305 | var div = domConstruct.create("div", {"class": this.baseClass+"Item"}); |
---|
306 | div.date = date; |
---|
307 | div.index = index; |
---|
308 | domConstruct.create('div',{ |
---|
309 | "class": this.baseClass + "ItemInner", |
---|
310 | innerHTML: dateString |
---|
311 | }, div); |
---|
312 | |
---|
313 | if(index%this._visibleIncrement<1 && index%this._visibleIncrement>-1){ |
---|
314 | domClass.add(div, this.baseClass+"Marker"); |
---|
315 | }else if(!(index%this._clickableIncrement)){ |
---|
316 | domClass.add(div, this.baseClass+"Tick"); |
---|
317 | } |
---|
318 | |
---|
319 | if(this.isDisabledDate(date)){ |
---|
320 | // set disabled |
---|
321 | domClass.add(div, this.baseClass+"ItemDisabled"); |
---|
322 | } |
---|
323 | if(this.value && !ddate.compare(this.value, date, this.constraints.selector)){ |
---|
324 | div.selected = true; |
---|
325 | domClass.add(div, this.baseClass+"ItemSelected"); |
---|
326 | if(domClass.contains(div, this.baseClass+"Marker")){ |
---|
327 | domClass.add(div, this.baseClass+"MarkerSelected"); |
---|
328 | }else{ |
---|
329 | domClass.add(div, this.baseClass+"TickSelected"); |
---|
330 | } |
---|
331 | |
---|
332 | // Initially highlight the current value. User can change highlight by up/down arrow keys |
---|
333 | // or mouse movement. |
---|
334 | this._highlightOption(div, true); |
---|
335 | } |
---|
336 | return div; |
---|
337 | }, |
---|
338 | |
---|
339 | _onOptionSelected: function(/*Object*/ tgt){ |
---|
340 | // summary: |
---|
341 | // Called when user clicks an option in the drop down list |
---|
342 | // tags: |
---|
343 | // private |
---|
344 | var tdate = tgt.target.date || tgt.target.parentNode.date; |
---|
345 | if(!tdate || this.isDisabledDate(tdate)){ return; } |
---|
346 | this._highlighted_option = null; |
---|
347 | this.set('value', tdate); |
---|
348 | this.onChange(tdate); |
---|
349 | }, |
---|
350 | |
---|
351 | onChange: function(/*Date*/ /*===== time =====*/){ |
---|
352 | // summary: |
---|
353 | // Notification that a time was selected. It may be the same as the previous value. |
---|
354 | // tags: |
---|
355 | // public |
---|
356 | }, |
---|
357 | |
---|
358 | _highlightOption: function(/*node*/ node, /*Boolean*/ highlight){ |
---|
359 | // summary: |
---|
360 | // Turns on/off highlight effect on a node based on mouse out/over event |
---|
361 | // tags: |
---|
362 | // private |
---|
363 | if(!node){return;} |
---|
364 | if(highlight){ |
---|
365 | if(this._highlighted_option){ |
---|
366 | this._highlightOption(this._highlighted_option, false); |
---|
367 | } |
---|
368 | this._highlighted_option = node; |
---|
369 | }else if(this._highlighted_option !== node){ |
---|
370 | return; |
---|
371 | }else{ |
---|
372 | this._highlighted_option = null; |
---|
373 | } |
---|
374 | domClass.toggle(node, this.baseClass+"ItemHover", highlight); |
---|
375 | if(domClass.contains(node, this.baseClass+"Marker")){ |
---|
376 | domClass.toggle(node, this.baseClass+"MarkerHover", highlight); |
---|
377 | }else{ |
---|
378 | domClass.toggle(node, this.baseClass+"TickHover", highlight); |
---|
379 | } |
---|
380 | }, |
---|
381 | |
---|
382 | onmouseover: function(/*Event*/ e){ |
---|
383 | // summary: |
---|
384 | // Handler for onmouseover event |
---|
385 | // tags: |
---|
386 | // private |
---|
387 | this._keyboardSelected = null; |
---|
388 | var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode; |
---|
389 | // if we aren't targeting an item, then we return |
---|
390 | if(!domClass.contains(tgr, this.baseClass+"Item")){return;} |
---|
391 | this._highlightOption(tgr, true); |
---|
392 | }, |
---|
393 | |
---|
394 | onmouseout: function(/*Event*/ e){ |
---|
395 | // summary: |
---|
396 | // Handler for onmouseout event |
---|
397 | // tags: |
---|
398 | // private |
---|
399 | this._keyboardSelected = null; |
---|
400 | var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode; |
---|
401 | this._highlightOption(tgr, false); |
---|
402 | }, |
---|
403 | |
---|
404 | _mouseWheeled: function(/*Event*/ e){ |
---|
405 | // summary: |
---|
406 | // Handle the mouse wheel events |
---|
407 | // tags: |
---|
408 | // private |
---|
409 | this._keyboardSelected = null; |
---|
410 | event.stop(e); |
---|
411 | // we're not _measuring_ the scroll amount, just direction |
---|
412 | var scrollAmount = (has("ie") ? e.wheelDelta : -e.detail); |
---|
413 | this[(scrollAmount>0 ? "_onArrowUp" : "_onArrowDown")](); // yes, we're making a new dom node every time you mousewheel, or click |
---|
414 | }, |
---|
415 | |
---|
416 | _onArrowUp: function(count){ |
---|
417 | // summary: |
---|
418 | // Handler for up arrow key. |
---|
419 | // description: |
---|
420 | // Removes the bottom time and add one to the top |
---|
421 | // tags: |
---|
422 | // private |
---|
423 | if(typeof count == "number" && count == -1){ return; } // typematic end |
---|
424 | if(!this.timeMenu.childNodes.length){ return; } |
---|
425 | var index = this.timeMenu.childNodes[0].index; |
---|
426 | var divs = this._getFilteredNodes(index, 1, true, this.timeMenu.childNodes[0]); |
---|
427 | if(divs.length){ |
---|
428 | this.timeMenu.removeChild(this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1]); |
---|
429 | this.timeMenu.insertBefore(divs[0], this.timeMenu.childNodes[0]); |
---|
430 | } |
---|
431 | }, |
---|
432 | |
---|
433 | _onArrowDown: function(count){ |
---|
434 | // summary: |
---|
435 | // Handler for up arrow key. |
---|
436 | // description: |
---|
437 | // Remove the top time and add one to the bottom |
---|
438 | // tags: |
---|
439 | // private |
---|
440 | if(typeof count == "number" && count == -1){ return; } // typematic end |
---|
441 | if(!this.timeMenu.childNodes.length){ return; } |
---|
442 | var index = this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1].index + 1; |
---|
443 | var divs = this._getFilteredNodes(index, 1, false, this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1]); |
---|
444 | if(divs.length){ |
---|
445 | this.timeMenu.removeChild(this.timeMenu.childNodes[0]); |
---|
446 | this.timeMenu.appendChild(divs[0]); |
---|
447 | } |
---|
448 | }, |
---|
449 | |
---|
450 | handleKey: function(/*Event*/ e){ |
---|
451 | // summary: |
---|
452 | // Called from `dijit.form._DateTimeTextBox` to pass a keypress event |
---|
453 | // from the `dijit.form.TimeTextBox` to be handled in this widget |
---|
454 | // tags: |
---|
455 | // protected |
---|
456 | if(e.charOrCode == keys.DOWN_ARROW || e.charOrCode == keys.UP_ARROW){ |
---|
457 | event.stop(e); |
---|
458 | // Figure out which option to highlight now and then highlight it |
---|
459 | if(this._highlighted_option && !this._highlighted_option.parentNode){ |
---|
460 | this._highlighted_option = null; |
---|
461 | } |
---|
462 | var timeMenu = this.timeMenu, |
---|
463 | tgt = this._highlighted_option || query("." + this.baseClass + "ItemSelected", timeMenu)[0]; |
---|
464 | if(!tgt){ |
---|
465 | tgt = timeMenu.childNodes[0]; |
---|
466 | }else if(timeMenu.childNodes.length){ |
---|
467 | if(e.charOrCode == keys.DOWN_ARROW && !tgt.nextSibling){ |
---|
468 | this._onArrowDown(); |
---|
469 | }else if(e.charOrCode == keys.UP_ARROW && !tgt.previousSibling){ |
---|
470 | this._onArrowUp(); |
---|
471 | } |
---|
472 | if(e.charOrCode == keys.DOWN_ARROW){ |
---|
473 | tgt = tgt.nextSibling; |
---|
474 | }else{ |
---|
475 | tgt = tgt.previousSibling; |
---|
476 | } |
---|
477 | } |
---|
478 | this._highlightOption(tgt, true); |
---|
479 | this._keyboardSelected = tgt; |
---|
480 | return false; |
---|
481 | }else if(e.charOrCode == keys.ENTER || e.charOrCode === keys.TAB){ |
---|
482 | // mouse hover followed by TAB is NO selection |
---|
483 | if(!this._keyboardSelected && e.charOrCode === keys.TAB){ |
---|
484 | return true; // true means don't call stopEvent() |
---|
485 | } |
---|
486 | |
---|
487 | // Accept the currently-highlighted option as the value |
---|
488 | if(this._highlighted_option){ |
---|
489 | this._onOptionSelected({target: this._highlighted_option}); |
---|
490 | } |
---|
491 | |
---|
492 | // Call stopEvent() for ENTER key so that form doesn't submit, |
---|
493 | // but not for TAB, so that TAB does switch focus |
---|
494 | return e.charOrCode === keys.TAB; |
---|
495 | } |
---|
496 | } |
---|
497 | }); |
---|
498 | }); |
---|