]> git.wh0rd.org Git - tt-rss.git/blob - lib/dijit/_TimePicker.js.uncompressed.js
add prototype simple remover of baaaad tags based on domdocument
[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 });