Roo/bootstrap/TimeField.js
[roojs1] / Roo / bootstrap / TimeField.js
1 /*
2  * - LGPL
3  *
4  * TimeField
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.TimeField
10  * @extends Roo.bootstrap.Input
11  * Bootstrap DateField class
12  * 
13  * 
14  * @constructor
15  * Create a new TimeField
16  * @param {Object} config The config object
17  */
18
19 Roo.bootstrap.TimeField = function(config){
20     Roo.bootstrap.TimeField.superclass.constructor.call(this, config);
21 };
22
23 Roo.extend(Roo.bootstrap.TimeField, Roo.bootstrap.Input,  {
24     
25     /**
26      * @cfg {String} format
27      * The default time format string which can be overriden for localization support.  The format must be
28      * valid according to {@link Date#parseDate} (defaults to 'H:i:s').
29      */
30     format : "H:i:s",
31     
32     
33     UTCDate: function()
34     {
35         return new Date(Date.UTC.apply(Date, arguments));
36     },
37     
38     UTCTime: function()
39     {
40         return new Date(Date.UTC.apply(Date, arguments));
41     },
42     
43     UTCToday: function()
44     {
45         var today = new Date();
46         return this.UTCDate(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate());
47     },
48     
49     UTCTodayTime: function()
50     {
51         var today = new Date();
52         return this.UTCTime(today.getUTCFullYear(), today.getUTCMonth(), today.getUTCDate(), today.getUTCHours(), today.getUTCMinutes());
53     },
54     
55     getDate: function() {
56             var d = this.getUTCDate();
57             return new Date(d.getTime() + (d.getTimezoneOffset()*60000));
58     },
59     
60     getUTCDate: function() {
61             return this.date;
62     },
63     
64     setDate: function(d) {
65             this.setUTCDate(new Date(d.getTime() - (d.getTimezoneOffset()*60000)));
66     },
67     
68     setUTCDate: function(d) {
69             this.date = d;
70             this.setValue(this.formatDate(this.date));
71     },
72         
73     onRender: function(ct, position)
74     {
75         
76         Roo.bootstrap.TimeField.superclass.onRender.call(this, ct, position);
77 //        
78 //        this.language = this.language || 'en';
79 //        this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : this.language.split('-')[0];
80 //        this.language = this.language in Roo.bootstrap.DateField.dates ? this.language : "en";
81 //        
82 //        this.isRTL = Roo.bootstrap.DateField.dates[this.language].rtl || false;
83 //        this.format = this.format || 'm/d/y';
84 //        this.isInline = false;
85 //        this.isInput = true;
86 //        this.component = this.el.select('.add-on', true).first() || false;
87 //        this.component = (this.component && this.component.length === 0) ? false : this.component;
88 //        this.hasInput = this.component && this.inputEL().length;
89         
90 //        if (typeof(this.minViewMode === 'string')) {
91 //            switch (this.minViewMode) {
92 //                case 'months':
93 //                    this.minViewMode = 2;
94 //                    break;
95 //                case 'years':
96 //                    this.minViewMode = 3;
97 //                    break;
98 //                case 'day':
99 //                    this.minViewMode = 1;
100 //                    break;
101 //                default:
102 //                    this.minViewMode = 0;
103 //                    break;
104 //            }
105 //        }
106         
107 //        if (typeof(this.viewMode === 'string')) {
108 //            switch (this.viewMode) {
109 //                case 'months':
110 //                    this.viewMode = 2;
111 //                    break;
112 //                case 'years':
113 //                    this.viewMode = 2;
114 //                    break;
115 //                case 'day':
116 //                    this.viewMode = 1;
117 //                    break;
118 //                default:
119 //                    this.viewMode = 0;
120 //                    break;
121 //            }
122 //        }
123                 
124         this.el.select('>.input-group', true).first().createChild(Roo.bootstrap.TimeField.template);
125         
126         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
127         
128         this.picker().on('mousedown', this.onMousedown, this);
129         this.picker().on('click', this.onClick, this);
130         
131         this.picker().addClass('datepicker-dropdown');
132         
133 //        this.startViewMode = this.viewMode;
134         
135 //        this.weekEnd = this.weekStart === 0 ? 6 : this.weekStart - 1;
136         
137 //        this.setStartDate(this.startDate);
138 //        this.setEndDate(this.endDate);
139         
140 //        this.setDaysOfWeekDisabled(this.daysOfWeekDisabled);
141         
142 //        this.fillDow();
143 //        this.fillMonths();
144         this.fillTime();
145         this.update();
146 //        this.showMode();
147         
148         if(this.showTime){
149             
150             var dayFoot = this.picker().select('>.datepicker-days tfoot th', true).first();
151             var timeFoot = this.picker().select('>.datepicker-time tfoot th', true).first();
152
153             var dayFootIcon = this.picker().select('>.datepicker-days tfoot span.picker-switch-icon', true).first();
154             var timeFootIcon = this.picker().select('>.datepicker-time tfoot span.picker-switch-icon', true).first();
155             
156             timeFoot.addClass('switch-calendar');
157             dayFoot.addClass('switch-time');
158             
159             timeFootIcon.addClass('switch-calendar');
160             timeFootIcon.addClass('glyphicon-calendar');
161             
162             dayFootIcon.addClass('switch-time');
163             dayFootIcon.addClass('glyphicon-time');
164             
165             var hours_up = this.picker().select('>.datepicker-time span.hours-up', true).first();
166             var hours_down = this.picker().select('>.datepicker-time span.hours-down', true).first();
167             var minutes_up = this.picker().select('>.datepicker-time span.minutes-up', true).first();
168             var minutes_down = this.picker().select('>.datepicker-time span.minutes-down', true).first();
169             
170             var period = this.picker().select('>.datepicker-time button', true).first();
171             
172             hours_up.on('click', this.onIncrementHours, hours_up);
173             hours_down.on('click', this.onDecrementHours, hours_down);
174             minutes_up.on('click', this.onIncrementMinutes, minutes_up);
175             minutes_down.on('click', this.onDecrementMinutes, minutes_down);
176             
177             period.on('click', this.onTogglePeriod, period);
178             
179         }else{
180             Roo.each(this.picker().select('tfoot th', true).elements, function(v){
181                 v.remove();
182             });
183         }
184         
185         if(this.isInline) {
186             this.show();
187         }
188     },
189     
190     picker : function()
191     {
192         return this.el.select('.datepicker', true).first();
193     },
194     
195     fillTime: function()
196     {    
197         var time = this.picker().select('>.datepicker-time tbody', true).first();
198         
199         time.dom.innerHTML = '';
200         
201         time.createChild({
202             tag: 'tr',
203             cn: [
204                 {
205                     tag: 'td',
206                     cn: [
207                         {
208                             tag: 'a',
209                             href: '#',
210                             cls: 'btn',
211                             cn: [
212                                 {
213                                     tag: 'span',
214                                     cls: 'hours-up glyphicon glyphicon-chevron-up'
215                                 }
216                             ]
217                         } 
218                     ]
219                 },
220                 {
221                     tag: 'td',
222                     cls: 'separator'
223                 },
224                 {
225                     tag: 'td',
226                     cn: [
227                         {
228                             tag: 'a',
229                             href: '#',
230                             cls: 'btn',
231                             cn: [
232                                 {
233                                     tag: 'span',
234                                     cls: 'minutes-up glyphicon glyphicon-chevron-up'
235                                 }
236                             ]
237                         }
238                     ]
239                 },
240                 {
241                     tag: 'td',
242                     cls: 'separator'
243                 }
244             ]
245         });
246         
247         time.createChild({
248             tag: 'tr',
249             cn: [
250                 {
251                     tag: 'td',
252                     cn: [
253                         {
254                             tag: 'span',
255                             cls: 'timepicker-hour',
256                             html: '00'
257                         }  
258                     ]
259                 },
260                 {
261                     tag: 'td',
262                     cls: 'separator',
263                     html: ':'
264                 },
265                 {
266                     tag: 'td',
267                     cn: [
268                         {
269                             tag: 'span',
270                             cls: 'timepicker-minute',
271                             html: '00'
272                         }  
273                     ]
274                 },
275                 {
276                     tag: 'td',
277                     cls: 'separator'
278                 },
279                 {
280                     tag: 'td',
281                     cn: [
282                         {
283                             tag: 'button',
284                             type: 'button',
285                             cls: 'btn btn-primary',
286                             html: 'AM'
287                             
288                         }
289                     ]
290                 }
291             ]
292         });
293         
294         time.createChild({
295             tag: 'tr',
296             cn: [
297                 {
298                     tag: 'td',
299                     cn: [
300                         {
301                             tag: 'a',
302                             href: '#',
303                             cls: 'btn',
304                             cn: [
305                                 {
306                                     tag: 'span',
307                                     cls: 'hours-down glyphicon glyphicon-chevron-down'
308                                 }
309                             ]
310                         }
311                     ]
312                 },
313                 {
314                     tag: 'td',
315                     cls: 'separator'
316                 },
317                 {
318                     tag: 'td',
319                     cn: [
320                         {
321                             tag: 'a',
322                             href: '#',
323                             cls: 'btn',
324                             cn: [
325                                 {
326                                     tag: 'span',
327                                     cls: 'minutes-down glyphicon glyphicon-chevron-down'
328                                 }
329                             ]
330                         }
331                     ]
332                 },
333                 {
334                     tag: 'td',
335                     cls: 'separator'
336                 }
337             ]
338         });
339         
340     },
341     
342     update: function()
343     {
344         
345         this.time = (typeof(this.time) === 'undefined') ? new Date() : this.time;
346         
347         this.fill();
348     },
349     
350     fill: function() 
351     {
352         
353         Roo.log(this.time.getHours());
354         Roo.log(this.time.get());
355         
356     },
357 //    
358 //    showMode: function(dir) {
359 //        if (dir) {
360 //            this.viewMode = Math.max(this.minViewMode, Math.min(3, this.viewMode + dir));
361 //        }
362 //        
363 //        Roo.each(this.picker().select('>div',true).elements, function(v){
364 //            v.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
365 //            v.hide();
366 //        });
367 //        this.picker().select('>.datepicker-'+Roo.bootstrap.DateField.modes[this.viewMode].clsName, true).first().show();
368 //        
369 //    },
370     
371     place: function()
372     {
373         if(this.isInline) return;
374         
375         this.picker().removeClass(['bottom', 'top']);
376         
377         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){
378             /*
379              * place to the top of element!
380              *
381              */
382             
383             this.picker().addClass('top');
384             this.picker().setTop(0 - this.picker().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
385             
386             return;
387         }
388         
389         this.picker().addClass('bottom');
390         
391         this.picker().setTop(this.inputEl().getHeight()).setLeft(this.inputEl().getLeft() - this.el.getLeft());
392     },
393     
394     parseDate : function(value){
395         if(!value || value instanceof Date){
396             return value;
397         }
398         var v = Date.parseDate(value, this.format);
399         if (!v && this.useIso) {
400             v = Date.parseDate(value, 'Y-m-d');
401         }
402         if(!v && this.altFormats){
403             if(!this.altFormatsArray){
404                 this.altFormatsArray = this.altFormats.split("|");
405             }
406             for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
407                 v = Date.parseDate(value, this.altFormatsArray[i]);
408             }
409         }
410         return v;
411     },
412     
413     formatDate : function(date, fmt){
414         return (!date || !(date instanceof Date)) ?
415         date : date.dateFormat(fmt || this.format);
416     },
417     
418     onFocus : function()
419     {
420         Roo.bootstrap.DateField.superclass.onFocus.call(this);
421         this.show();
422     },
423     
424     onBlur : function()
425     {
426         Roo.bootstrap.DateField.superclass.onBlur.call(this);
427         this.hide();
428     },
429     
430     show : function()
431     {
432         this.picker().show();
433         this.update();
434         this.place();
435     },
436     
437     hide : function()
438     {
439         this.picker().hide();
440         
441     },
442     
443     onMousedown: function(e){
444         e.stopPropagation();
445         e.preventDefault();
446     },
447     
448     keyup: function(e){
449         Roo.bootstrap.DateField.superclass.keyup.call(this);
450         this.update();
451         
452     },
453     
454     fireKey: function(e){
455         if (!this.picker().isVisible()){
456             if (e.keyCode == 27) // allow escape to hide and re-show picker
457                 this.show();
458             return;
459         }
460         var dateChanged = false,
461         dir, day, month,
462         newDate, newViewDate;
463         switch(e.keyCode){
464             case 27: // escape
465                 this.hide();
466                 e.preventDefault();
467                 break;
468             case 37: // left
469             case 39: // right
470                 if (!this.keyboardNavigation) break;
471                 dir = e.keyCode == 37 ? -1 : 1;
472                 
473                 if (e.ctrlKey){
474                     newDate = this.moveYear(this.date, dir);
475                     newViewDate = this.moveYear(this.viewDate, dir);
476                 } else if (e.shiftKey){
477                     newDate = this.moveMonth(this.date, dir);
478                     newViewDate = this.moveMonth(this.viewDate, dir);
479                 } else {
480                     newDate = new Date(this.date);
481                     newDate.setUTCDate(this.date.getUTCDate() + dir);
482                     newViewDate = new Date(this.viewDate);
483                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir);
484                 }
485                 if (this.dateWithinRange(newDate)){
486                     this.date = newDate;
487                     this.viewDate = newViewDate;
488                     this.setValue(this.formatDate(this.date));
489                     this.update();
490                     e.preventDefault();
491                     dateChanged = true;
492                 }
493                 break;
494             case 38: // up
495             case 40: // down
496                 if (!this.keyboardNavigation) break;
497                 dir = e.keyCode == 38 ? -1 : 1;
498                 if (e.ctrlKey){
499                     newDate = this.moveYear(this.date, dir);
500                     newViewDate = this.moveYear(this.viewDate, dir);
501                 } else if (e.shiftKey){
502                     newDate = this.moveMonth(this.date, dir);
503                     newViewDate = this.moveMonth(this.viewDate, dir);
504                 } else {
505                     newDate = new Date(this.date);
506                     newDate.setUTCDate(this.date.getUTCDate() + dir * 7);
507                     newViewDate = new Date(this.viewDate);
508                     newViewDate.setUTCDate(this.viewDate.getUTCDate() + dir * 7);
509                 }
510                 if (this.dateWithinRange(newDate)){
511                     this.date = newDate;
512                     this.viewDate = newViewDate;
513                     this.setValue(this.formatDate(this.date));
514                     this.update();
515                     e.preventDefault();
516                     dateChanged = true;
517                 }
518                 break;
519             case 13: // enter
520                 this.setValue(this.formatDate(this.date));
521                 this.hide();
522                 e.preventDefault();
523                 break;
524             case 9: // tab
525                 this.setValue(this.formatDate(this.date));
526                 this.hide();
527                 break;
528         }
529     },
530     
531     
532     onClick: function(e) {
533         e.stopPropagation();
534         e.preventDefault();
535         
536         var target = e.getTarget();
537         
538         if(target.nodeName.toLowerCase() === 'i'){
539             target = Roo.get(target).dom.parentNode;
540         }
541         
542         var nodeName = target.nodeName.trim();
543         var className = target.className.trim();
544         var html = target.innerHTML;
545         
546         switch(nodeName.toLowerCase()) {
547             case 'th':
548                 switch(className) {
549                     case 'switch':
550                         this.showMode(1);
551                         break;
552                     case 'prev':
553                     case 'next':
554                         var dir = Roo.bootstrap.DateField.modes[this.viewMode].navStep * (className == 'prev' ? -1 : 1);
555                         switch(this.viewMode){
556                                 case 0:
557                                         this.viewDate = this.moveMonth(this.viewDate, dir);
558                                         break;
559                                 case 1:
560                                 case 2:
561                                         this.viewDate = this.moveYear(this.viewDate, dir);
562                                         break;
563                         }
564                         this.fill();
565                         break;
566                     case 'today':
567                         var date = new Date();
568                         this.date = this.UTCDate(date.getFullYear(), date.getMonth(), date.getDate(), 0, 0, 0);
569                         this.fill()
570                         this.setValue(this.formatDate(this.date));
571                         this.hide();
572                         break;
573                      case 'switch-time':
574                         this.showMode(-1);
575                         this.fill();
576                         break;
577                      case 'switch-calendar':
578                          this.showMode(1);
579                          this.fill();
580                          break;
581                 }
582                 break;
583             case 'span':
584                 if (className.indexOf('disabled') === -1) {
585                     this.viewDate.setUTCDate(1);
586                     if (className.indexOf('month') !== -1) {
587                         this.viewDate.setUTCMonth(Roo.bootstrap.DateField.dates[this.language].monthsShort.indexOf(html));
588                     } else if(className.indexOf('picker-switch-icon') !== -1){
589                         if(className.indexOf('switch-time') !== -1){
590                             this.showMode(-1);
591                             this.fill();
592                         }else{
593                             this.showMode(1);
594                             this.fill();
595                         }
596                         
597                         break;
598                         
599                     } else {
600                         var year = parseInt(html, 10) || 0;
601                         this.viewDate.setUTCFullYear(year);
602                         
603                     }
604                     this.showMode(-1);
605                     this.fill();
606                 }
607                 break;
608                 
609             case 'td':
610                 if (className.indexOf('day') !== -1 && className.indexOf('disabled') === -1){
611                     var day = parseInt(html, 10) || 1;
612                     var year = this.viewDate.getUTCFullYear(),
613                         month = this.viewDate.getUTCMonth();
614
615                     if (className.indexOf('old') !== -1) {
616                         if(month === 0 ){
617                             month = 11;
618                             year -= 1;
619                         }else{
620                             month -= 1;
621                         }
622                     } else if (className.indexOf('new') !== -1) {
623                         if (month == 11) {
624                             month = 0;
625                             year += 1;
626                         } else {
627                             month += 1;
628                         }
629                     }
630                     this.date = this.UTCDate(year, month, day,0,0,0,0);
631                     this.viewDate = this.UTCDate(year, month, Math.min(28, day),0,0,0,0);
632                     this.fill();
633                     this.setValue(this.formatDate(this.date));
634                     this.hide();
635                 }
636                 break;
637         }
638     },
639     
640     setStartDate: function(startDate){
641         this.startDate = startDate || -Infinity;
642         if (this.startDate !== -Infinity) {
643             this.startDate = this.parseDate(this.startDate);
644         }
645         this.update();
646         this.updateNavArrows();
647     },
648
649     setEndDate: function(endDate){
650         this.endDate = endDate || Infinity;
651         if (this.endDate !== Infinity) {
652             this.endDate = this.parseDate(this.endDate);
653         }
654         this.update();
655         this.updateNavArrows();
656     },
657     
658     setDaysOfWeekDisabled: function(daysOfWeekDisabled){
659         this.daysOfWeekDisabled = daysOfWeekDisabled || [];
660         if (typeof(this.daysOfWeekDisabled) !== 'object') {
661             this.daysOfWeekDisabled = this.daysOfWeekDisabled.split(/,\s*/);
662         }
663         this.daysOfWeekDisabled = this.daysOfWeekDisabled.map(function (d) {
664             return parseInt(d, 10);
665         });
666         this.update();
667         this.updateNavArrows();
668     },
669     
670     updateNavArrows: function() {
671         var d = new Date(this.viewDate),
672         year = d.getUTCFullYear(),
673         month = d.getUTCMonth();
674         
675         Roo.each(this.picker().select('.prev', true).elements, function(v){
676             v.show();
677             switch (this.viewMode) {
678                 case 0:
679
680                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear() && month <= this.startDate.getUTCMonth()) {
681                         v.hide();
682                     }
683                     break;
684                 case 1:
685                 case 2:
686                     if (this.startDate !== -Infinity && year <= this.startDate.getUTCFullYear()) {
687                         v.hide();
688                     }
689                     break;
690             }
691         });
692         
693         Roo.each(this.picker().select('.next', true).elements, function(v){
694             v.show();
695             switch (this.viewMode) {
696                 case 0:
697
698                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear() && month >= this.endDate.getUTCMonth()) {
699                         v.hide();
700                     }
701                     break;
702                 case 1:
703                 case 2:
704                     if (this.endDate !== Infinity && year >= this.endDate.getUTCFullYear()) {
705                         v.hide();
706                     }
707                     break;
708             }
709         })
710     },
711     
712     moveMonth: function(date, dir){
713         if (!dir) return date;
714         var new_date = new Date(date.valueOf()),
715         day = new_date.getUTCDate(),
716         month = new_date.getUTCMonth(),
717         mag = Math.abs(dir),
718         new_month, test;
719         dir = dir > 0 ? 1 : -1;
720         if (mag == 1){
721             test = dir == -1
722             // If going back one month, make sure month is not current month
723             // (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)
724             ? function(){
725                 return new_date.getUTCMonth() == month;
726             }
727             // If going forward one month, make sure month is as expected
728             // (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)
729             : function(){
730                 return new_date.getUTCMonth() != new_month;
731             };
732             new_month = month + dir;
733             new_date.setUTCMonth(new_month);
734             // Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11
735             if (new_month < 0 || new_month > 11)
736                 new_month = (new_month + 12) % 12;
737         } else {
738             // For magnitudes >1, move one month at a time...
739             for (var i=0; i<mag; i++)
740                 // ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...
741                 new_date = this.moveMonth(new_date, dir);
742             // ...then reset the day, keeping it in the new month
743             new_month = new_date.getUTCMonth();
744             new_date.setUTCDate(day);
745             test = function(){
746                 return new_month != new_date.getUTCMonth();
747             };
748         }
749         // Common date-resetting loop -- if date is beyond end of month, make it
750         // end of month
751         while (test()){
752             new_date.setUTCDate(--day);
753             new_date.setUTCMonth(new_month);
754         }
755         return new_date;
756     },
757
758     moveYear: function(date, dir){
759         return this.moveMonth(date, dir*12);
760     },
761
762     dateWithinRange: function(date){
763         return date >= this.startDate && date <= this.endDate;
764     },
765
766     remove: function() {
767         this.picker().remove();
768     },
769     
770     onIncrementHours: function()
771     {
772         Roo.log('onIncrementHours');
773     },
774     
775     onDecrementHours: function()
776     {
777         Roo.log('onDecrementHours');
778     },
779     
780     onIncrementMinutes: function()
781     {
782         Roo.log('onIncrementMinutes');
783     },
784     
785     onDecrementMinutes: function()
786     {
787         Roo.log('onDecrementMinutes');
788     },
789     
790     onTogglePeriod: function()
791     {
792         Roo.log('onTogglePeriod');
793     }
794     
795    
796 });
797
798 Roo.apply(Roo.bootstrap.TimeField,  {
799     
800     content : {
801         tag: 'tbody',
802         cn: [
803         {
804             tag: 'tr',
805             cn: [
806             {
807                 tag: 'td',
808                 colspan: '7'
809             }
810             ]
811         }
812         ]
813     }
814 });
815
816 Roo.apply(Roo.bootstrap.TimeField,  {
817   
818     template : {
819         tag: 'div',
820         cls: 'datepicker dropdown-menu',
821         cn: [
822             {
823                 tag: 'div',
824                 cls: 'datepicker-time',
825                 cn: [
826                 {
827                     tag: 'table',
828                     cls: 'table-condensed',
829                     cn:[
830                     Roo.bootstrap.DateField.content
831                     ]
832                 }
833                 ]
834             }
835         ]
836     }
837 });
838
839  
840
841