]> git.wh0rd.org - tt-rss.git/blob - lib/dijit/_TimePicker.js.uncompressed.js
upgrade dojo to 1.8.3 (refs #570)
[tt-rss.git] / lib / dijit / _TimePicker.js.uncompressed.js
1 require({cache:{
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\">&#160;</div\n\t\t><div class=\"dijitArrowButtonChar\">&#9650;</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\">&#160;</div\n\t\t><div class=\"dijitArrowButtonChar\">&#9660;</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
13 "dojo/keys", // keys
14 "dojo/_base/lang", // lang.mixin
15 "dojo/sniff", // has(...)
16 "dojo/query", // query
17 "dojo/mouse", // mouse.wheel
18 "./typematic",
19 "./_Widget",
20 "./_TemplatedMixin",
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){
25
26 // module:
27 // dijit/_TimePicker
28
29
30 var TimePicker = declare("dijit._TimePicker", [_Widget, _TemplatedMixin], {
31 // summary:
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.
35
36 templateString: template,
37
38 // baseClass: [protected] String
39 // The root className to use for the various states of this widget
40 baseClass: "dijitTimePicker",
41
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",
49
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",
56
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",
62
63 // value: String
64 // Date to display.
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`
77 value: new Date(),
78
79 _visibleIncrement:2,
80 _clickableIncrement:1,
81 _totalIncrements:10,
82
83 // constraints: TimePicker.__Constraints
84 // Specifies valid range of times (start time, end time)
85 constraints:{},
86
87 /*=====
88 serialize: function(val, options){
89 // summary:
90 // User overridable function used to convert the attr('value') result to a String
91 // val: Date
92 // The current value
93 // options: Object?
94 // tags:
95 // protected
96 },
97 =====*/
98 serialize: stamp.toISOString,
99
100 /*=====
101 // filterString: string
102 // The string to filter by
103 filterString: "",
104 =====*/
105
106 setValue: function(/*Date*/ value){
107 // summary:
108 // Deprecated. Used set('value') instead.
109 // tags:
110 // deprecated
111 kernel.deprecated("dijit._TimePicker:setValue() is deprecated. Use set('value', ...) instead.", "", "2.0");
112 this.set('value', value);
113 },
114
115 _setValueAttr: function(/*Date*/ date){
116 // summary:
117 // Hook so set('value', ...) works.
118 // description:
119 // Set the value of the TimePicker.
120 // Redraws the TimePicker around the new date.
121 // tags:
122 // protected
123 this._set("value", date);
124 this._showText();
125 },
126
127 _setFilterStringAttr: function(val){
128 // summary:
129 // Called by TimeTextBox to filter the values shown in my list
130 this._set("filterString", val);
131 this._showText();
132 },
133
134 isDisabledDate: function(/*===== dateObject, locale =====*/){
135 // summary:
136 // May be overridden to disable certain dates in the TimePicker e.g. `isDisabledDate=locale.isWeekend`
137 // dateObject: Date
138 // locale: String?
139 // type:
140 // extension
141 return false; // Boolean
142 },
143
144 _getFilteredNodes: function(/*number*/ start, /*number*/ maxNum, /*Boolean*/ before, /*DOMnode*/ lastNode){
145 // summary:
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
150 // tags:
151 // private
152 var
153 nodes = [],
154 lastValue = lastNode ? lastNode.date : this._refDate,
155 n,
156 i = start,
157 max = this._maxIncrement + Math.abs(i),
158 chk = before ? -1 : 1,
159 dec = before ? 1 : 0,
160 inc = 1 - dec;
161 do{
162 i -= dec;
163 n = this._createOption(i);
164 if(n){
165 if((before && n.date > lastValue) || (!before && n.date < lastValue)){
166 break; // don't wrap
167 }
168 nodes[before ? "unshift" : "push"](n);
169 lastValue = n.date;
170 }
171 i += inc;
172 }while(nodes.length < maxNum && (i*chk) < max);
173 return nodes;
174 },
175
176 _showText: function(){
177 // summary:
178 // Displays the relevant choices in the drop down list
179 // tags:
180 // private
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
187 var
188 sinceMidnight = function(/*Date*/ date){
189 return date.getHours() * 60 * 60 + date.getMinutes() * 60 + date.getSeconds();
190 },
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();
196
197 this._refDate = new Date(time - time % (clickableIncrementSeconds*1000));
198 this._refDate.setFullYear(1970,0,1); // match parse defaults
199
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;
211
212 var
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),
217 moreAfter = [],
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]);
222 }
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 = '';
227 this._showText();
228 }
229 },
230
231 constructor: function(/*===== params, srcNodeRef =====*/){
232 // summary:
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
240
241 this.constraints = {};
242 },
243
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
247 },
248
249 _setConstraintsAttr: function(/* Object */ constraints){
250 // brings in visibleRange, increments, etc.
251 lang.mixin(this, constraints);
252
253 // locale needs the lang in the constraints as locale
254 if(!constraints.locale){
255 constraints.locale = this.lang;
256 }
257 },
258
259 postCreate: function(){
260 // assign typematic mouse listeners to the arrow buttons
261 this.connect(this.timeMenu, mouse.wheel, "_mouseWheeled");
262 this.own(
263 typematic.addMouseListener(this.upArrow, this, "_onArrowUp", 33, 250),
264 typematic.addMouseListener(this.downArrow, this, "_onArrowDown", 33, 250)
265 );
266
267 this.inherited(arguments);
268 },
269
270 _buttonMouse: function(/*Event*/ e){
271 // summary:
272 // Handler for hover (and unhover) on up/down arrows
273 // tags:
274 // private
275
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");
280 },
281
282 _createOption: function(/*Number*/ index){
283 // summary:
284 // Creates a clickable time option
285 // tags:
286 // private
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
295 }
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
299 return null;
300 }
301
302 var div = this.ownerDocument.createElement("div");
303 div.className = this.baseClass+"Item";
304 div.date = date;
305 div.idx = index;
306 domConstruct.create('div',{
307 "class": this.baseClass + "ItemInner",
308 innerHTML: dateString
309 }, div);
310
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");
315 }
316
317 if(this.isDisabledDate(date)){
318 // set disabled
319 domClass.add(div, this.baseClass+"ItemDisabled");
320 }
321 if(this.value && !ddate.compare(this.value, date, this.constraints.selector)){
322 div.selected = true;
323 domClass.add(div, this.baseClass+"ItemSelected");
324 if(domClass.contains(div, this.baseClass+"Marker")){
325 domClass.add(div, this.baseClass+"MarkerSelected");
326 }else{
327 domClass.add(div, this.baseClass+"TickSelected");
328 }
329
330 // Initially highlight the current value. User can change highlight by up/down arrow keys
331 // or mouse movement.
332 this._highlightOption(div, true);
333 }
334 return div;
335 },
336
337 _onOptionSelected: function(/*Object*/ tgt){
338 // summary:
339 // Called when user clicks an option in the drop down list
340 // tags:
341 // private
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);
347 },
348
349 onChange: function(/*Date*/ /*===== time =====*/){
350 // summary:
351 // Notification that a time was selected. It may be the same as the previous value.
352 // tags:
353 // public
354 },
355
356 _highlightOption: function(/*node*/ node, /*Boolean*/ highlight){
357 // summary:
358 // Turns on/off highlight effect on a node based on mouse out/over event
359 // tags:
360 // private
361 if(!node){return;}
362 if(highlight){
363 if(this._highlighted_option){
364 this._highlightOption(this._highlighted_option, false);
365 }
366 this._highlighted_option = node;
367 }else if(this._highlighted_option !== node){
368 return;
369 }else{
370 this._highlighted_option = null;
371 }
372 domClass.toggle(node, this.baseClass+"ItemHover", highlight);
373 if(domClass.contains(node, this.baseClass+"Marker")){
374 domClass.toggle(node, this.baseClass+"MarkerHover", highlight);
375 }else{
376 domClass.toggle(node, this.baseClass+"TickHover", highlight);
377 }
378 },
379
380 onmouseover: function(/*Event*/ e){
381 // summary:
382 // Handler for onmouseover event
383 // tags:
384 // private
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);
390 },
391
392 onmouseout: function(/*Event*/ e){
393 // summary:
394 // Handler for onmouseout event
395 // tags:
396 // private
397 this._keyboardSelected = null;
398 var tgr = (e.target.parentNode === this.timeMenu) ? e.target : e.target.parentNode;
399 this._highlightOption(tgr, false);
400 },
401
402 _mouseWheeled: function(/*Event*/ e){
403 // summary:
404 // Handle the mouse wheel events
405 // tags:
406 // private
407 this._keyboardSelected = null;
408 event.stop(e);
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
411 },
412
413 _onArrowUp: function(count){
414 // summary:
415 // Handler for up arrow key.
416 // description:
417 // Removes the bottom time and add one to the top
418 // tags:
419 // private
420 if(count === -1){
421 domClass.remove(this.upArrow, "dijitUpArrowActive");
422 return;
423 }else if(count === 0){
424 domClass.add(this.upArrow, "dijitUpArrowActive");
425
426 } // typematic end
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]);
430 if(divs.length){
431 this.timeMenu.removeChild(this.timeMenu.childNodes[this.timeMenu.childNodes.length - 1]);
432 this.timeMenu.insertBefore(divs[0], this.timeMenu.childNodes[0]);
433 }
434 },
435
436 _onArrowDown: function(count){
437 // summary:
438 // Handler for up arrow key.
439 // description:
440 // Remove the top time and add one to the bottom
441 // tags:
442 // private
443 if(count === -1){
444 domClass.remove(this.downArrow, "dijitDownArrowActive");
445 return;
446 }else if(count === 0){
447 domClass.add(this.downArrow, "dijitDownArrowActive");
448 } // typematic end
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]);
452 if(divs.length){
453 this.timeMenu.removeChild(this.timeMenu.childNodes[0]);
454 this.timeMenu.appendChild(divs[0]);
455 }
456 },
457
458 handleKey: function(/*Event*/ e){
459 // summary:
460 // Called from `dijit/form/_DateTimeTextBox` to pass a keypress event
461 // from the `dijit/form/TimeTextBox` to be handled in this widget
462 // tags:
463 // protected
464 if(e.keyCode == keys.DOWN_ARROW || e.keyCode == keys.UP_ARROW){
465 event.stop(e);
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;
469 }
470 var timeMenu = this.timeMenu,
471 tgt = this._highlighted_option || query("." + this.baseClass + "ItemSelected", timeMenu)[0];
472 if(!tgt){
473 tgt = timeMenu.childNodes[0];
474 }else if(timeMenu.childNodes.length){
475 if(e.keyCode == keys.DOWN_ARROW && !tgt.nextSibling){
476 this._onArrowDown();
477 }else if(e.keyCode == keys.UP_ARROW && !tgt.previousSibling){
478 this._onArrowUp();
479 }
480 if(e.keyCode == keys.DOWN_ARROW){
481 tgt = tgt.nextSibling;
482 }else{
483 tgt = tgt.previousSibling;
484 }
485 }
486 this._highlightOption(tgt, true);
487 this._keyboardSelected = tgt;
488 return false;
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()
493 }
494
495 // Accept the currently-highlighted option as the value
496 if(this._highlighted_option){
497 this._onOptionSelected({target: this._highlighted_option});
498 }
499
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;
503 }
504 return undefined;
505 }
506 });
507
508 /*=====
509 TimePicker.__Constraints = declare(locale.__FormatOptions, {
510 // clickableIncrement: String
511 // See `dijit/_TimePicker.clickableIncrement`
512 clickableIncrement: "T00:15:00",
513
514 // visibleIncrement: String
515 // See `dijit/_TimePicker.visibleIncrement`
516 visibleIncrement: "T01:00:00",
517
518 // visibleRange: String
519 // See `dijit/_TimePicker.visibleRange`
520 visibleRange: "T05:00:00"
521 });
522 =====*/
523
524 return TimePicker;
525 });