set up time if empty
[roojs1] / Roo / bootstrap / form / TimeField.js
1 /*
2  * - LGPL
3  *
4  * TimeField
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.form.TimeField
10  * @extends Roo.bootstrap.form.Input
11  * Bootstrap DateField class
12  * @cfg {Number} minuteStep the minutes is always the multiple of a fixed number, default 1
13  * 
14  * 
15  * @constructor
16  * Create a new TimeField
17  * @param {Object} config The config object
18  */
19
20 Roo.bootstrap.form.TimeField = function(config){
21     Roo.bootstrap.form.TimeField.superclass.constructor.call(this, config);
22     this.addEvents({
23             /**
24              * @event show
25              * Fires when this field show.
26              * @param {Roo.bootstrap.form.DateField} thisthis
27              * @param {Mixed} date The date value
28              */
29             show : true,
30             /**
31              * @event show
32              * Fires when this field hide.
33              * @param {Roo.bootstrap.form.DateField} this
34              * @param {Mixed} date The date value
35              */
36             hide : true,
37             /**
38              * @event select
39              * Fires when select a date.
40              * @param {Roo.bootstrap.form.DateField} this
41              * @param {Mixed} date The date value
42              */
43             select : true
44         });
45 };
46
47 Roo.extend(Roo.bootstrap.form.TimeField, Roo.bootstrap.form.Input,  {
48     
49     /**
50      * @cfg {String} format
51      * The default time format string which can be overriden for localization support.  The format must be
52      * valid according to {@link Date#parseDate} (defaults to 'H:i').
53      */
54     format : "H:i",
55     minuteStep : 1,
56     language : 'en',
57     hiddenField : false,
58     getAutoCreate : function()
59     {
60         this.after = '<i class="fa far fa-clock"></i>';
61         return Roo.bootstrap.form.TimeField.superclass.getAutoCreate.call(this);
62         
63          
64     },
65     onRender: function(ct, position)
66     {
67         
68         Roo.bootstrap.form.TimeField.superclass.onRender.call(this, ct, position);
69
70         this.language = this.language in Roo.bootstrap.form.TimeField.periodText ? this.language : "en";
71                 
72         this.pickerEl = Roo.get(document.body).createChild(Roo.bootstrap.form.TimeField.template);
73         
74         this.picker().setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
75         
76         this.pop = this.picker().select('>.datepicker-time',true).first();
77         this.pop.setVisibilityMode(Roo.Element.DISPLAY).originalDisplay = 'block';
78         
79         this.picker().on('mousedown', this.onMousedown, this);
80         this.picker().on('click', this.onClick, this);
81         
82         this.picker().addClass('datepicker-dropdown');
83     
84         this.fillTime();
85         this.update();
86             
87         this.pop.select('.hours-up', true).first().on('click', this.onIncrementHours, this);
88         this.pop.select('.hours-down', true).first().on('click', this.onDecrementHours, this);
89         this.pop.select('.minutes-up', true).first().on('click', this.onIncrementMinutes, this);
90         this.pop.select('.minutes-down', true).first().on('click', this.onDecrementMinutes, this);
91         this.pop.select('button.period', true).first().on('click', this.onTogglePeriod, this);
92         this.pop.select('button.ok', true).first().on('click', this.setTime, this);
93         this.pop.select('button.ok', true).first().dom.innerHTML = Roo.bootstrap.form.TimeField.okText;
94
95         this.hiddenField = this.inputEl().insertSibling(
96             {tag : 'input', type : 'hidden', name : this.name},
97             'before',
98             true
99         );
100         this.inputEl().dom.setAttribute('name', this.name + '____hidden___');
101
102     },
103     
104     fireKey: function(e){
105         if (!this.picker().isVisible()){
106             if (e.keyCode == 27) { // allow escape to hide and re-show picker
107                 this.show();
108             }
109             return;
110         }
111
112         e.preventDefault();
113         
114         switch(e.keyCode){
115             case 27: // escape
116                 this.hide();
117                 break;
118             case 37: // left
119             case 39: // right
120                 this.onTogglePeriod();
121                 break;
122             case 38: // up
123                 this.onIncrementMinutes();
124                 break;
125             case 40: // down
126                 this.onDecrementMinutes();
127                 break;
128             case 13: // enter
129             case 9: // tab
130                 this.setTime();
131                 break;
132         }
133     },
134     
135     onClick: function(e) {
136         e.stopPropagation();
137         e.preventDefault();
138     },
139     
140     picker : function()
141     {
142         return this.pickerEl;
143     },
144     
145     fillTime: function()
146     {    
147         var time = this.pop.select('tbody', true).first();
148         
149         time.dom.innerHTML = '';
150         
151         time.createChild({
152             tag: 'tr',
153             cn: [
154                 {
155                     tag: 'td',
156                     cn: [
157                         {
158                             tag: 'a',
159                             href: '#',
160                             cls: 'btn',
161                             cn: [
162                                 {
163                                     tag: 'i',
164                                     cls: 'hours-up fa fas fa-chevron-up'
165                                 }
166                             ]
167                         } 
168                     ]
169                 },
170                 {
171                     tag: 'td',
172                     cls: 'separator'
173                 },
174                 {
175                     tag: 'td',
176                     cn: [
177                         {
178                             tag: 'a',
179                             href: '#',
180                             cls: 'btn',
181                             cn: [
182                                 {
183                                     tag: 'i',
184                                     cls: 'minutes-up fa fas fa-chevron-up'
185                                 }
186                             ]
187                         }
188                     ]
189                 },
190                 {
191                     tag: 'td',
192                     cls: 'separator'
193                 }
194             ]
195         });
196         
197         time.createChild({
198             tag: 'tr',
199             cn: [
200                 {
201                     tag: 'td',
202                     cn: [
203                         {
204                             tag: 'span',
205                             cls: 'timepicker-hour',
206                             html: '00'
207                         }  
208                     ]
209                 },
210                 {
211                     tag: 'td',
212                     cls: 'separator',
213                     html: ':'
214                 },
215                 {
216                     tag: 'td',
217                     cn: [
218                         {
219                             tag: 'span',
220                             cls: 'timepicker-minute',
221                             html: '00'
222                         }  
223                     ]
224                 },
225                 {
226                     tag: 'td',
227                     cls: 'separator'
228                 },
229                 {
230                     tag: 'td',
231                     cn: [
232                         {
233                             tag: 'button',
234                             type: 'button',
235                             cls: 'btn btn-primary period',
236                             html: 'AM'
237                             
238                         }
239                     ]
240                 }
241             ]
242         });
243         
244         time.createChild({
245             tag: 'tr',
246             cn: [
247                 {
248                     tag: 'td',
249                     cn: [
250                         {
251                             tag: 'a',
252                             href: '#',
253                             cls: 'btn',
254                             cn: [
255                                 {
256                                     tag: 'span',
257                                     cls: 'hours-down fa fas fa-chevron-down'
258                                 }
259                             ]
260                         }
261                     ]
262                 },
263                 {
264                     tag: 'td',
265                     cls: 'separator'
266                 },
267                 {
268                     tag: 'td',
269                     cn: [
270                         {
271                             tag: 'a',
272                             href: '#',
273                             cls: 'btn',
274                             cn: [
275                                 {
276                                     tag: 'span',
277                                     cls: 'minutes-down fa fas fa-chevron-down'
278                                 }
279                             ]
280                         }
281                     ]
282                 },
283                 {
284                     tag: 'td',
285                     cls: 'separator'
286                 }
287             ]
288         });
289         
290     },
291     
292     update: function()
293     {
294         // default minute is a multiple of minuteStep
295         if(typeof(this.time) === 'undefined' || this.time.length == 0) {
296             this.time = new Date();
297             this.time = this.time.add(Date.MINUTE, Math.round(parseInt(this.time.format('i')) / this.minuteStep) * this.minuteStep - parseInt(this.time.format('i')));
298         }
299         this.time = (typeof(this.time) === 'undefined' || this.time.length == 0) ? new Date() : this.time;
300         
301         this.fill();
302     },
303     
304     fill: function() 
305     {
306         var hours = this.time.getHours();
307         var minutes = this.time.getMinutes();
308         var period = Roo.bootstrap.form.TimeField.periodText[this.language]['am'];
309         
310         if(hours > 11){
311             period = Roo.bootstrap.form.TimeField.periodText[this.language]['pm'];
312         }
313         
314         if(hours == 0){
315             hours = 12;
316         }
317         
318         
319         if(hours > 12){
320             hours = hours - 12;
321         }
322         
323         if(hours < 10){
324             hours = '0' + hours;
325         }
326         
327         if(minutes < 10){
328             minutes = '0' + minutes;
329         }
330         
331         this.pop.select('.timepicker-hour', true).first().dom.innerHTML = hours;
332         this.pop.select('.timepicker-minute', true).first().dom.innerHTML = minutes;
333         this.pop.select('button', true).first().dom.innerHTML = period;
334         
335     },
336     
337     place: function()
338     {   
339         this.picker().removeClass(['bottom-left', 'bottom-right', 'top-left', 'top-right']);
340         
341         var cls = ['bottom'];
342         
343         if((Roo.lib.Dom.getViewHeight() + Roo.get(document.body).getScroll().top) - (this.inputEl().getBottom() + this.picker().getHeight()) < 0){ // top
344             cls.pop();
345             cls.push('top');
346         }
347         
348         cls.push('right');
349         
350         if((Roo.lib.Dom.getViewWidth() + Roo.get(document.body).getScroll().left) - (this.inputEl().getLeft() + this.picker().getWidth()) < 0){ // left
351             cls.pop();
352             cls.push('left');
353         }
354         //this.picker().setXY(20000,20000);
355         this.picker().addClass(cls.join('-'));
356         
357         var _this = this;
358         
359         Roo.each(cls, function(c){
360             if(c == 'bottom'){
361                 (function() {
362                  //  
363                 }).defer(200);
364                  _this.picker().alignTo(_this.inputEl(),   "tr-br", [0, 10], false);
365                 //_this.picker().setTop(_this.inputEl().getHeight());
366                 return;
367             }
368             if(c == 'top'){
369                  _this.picker().alignTo(_this.inputEl(),   "br-tr", [0, 10], false);
370                 
371                 //_this.picker().setTop(0 - _this.picker().getHeight());
372                 return;
373             }
374             /*
375             if(c == 'left'){
376                 _this.picker().setLeft(_this.inputEl().getLeft() + _this.inputEl().getWidth() - _this.el.getLeft() - _this.picker().getWidth());
377                 return;
378             }
379             if(c == 'right'){
380                 _this.picker().setLeft(_this.inputEl().getLeft() - _this.el.getLeft());
381                 return;
382             }
383             */
384         });
385         
386     },
387   
388     onFocus : function()
389     {
390         Roo.bootstrap.form.TimeField.superclass.onFocus.call(this);
391         this.show();
392     },
393     
394     onBlur : function()
395     {
396         Roo.bootstrap.form.TimeField.superclass.onBlur.call(this);
397         this.hide();
398     },
399     
400     show : function()
401     {
402         this.picker().show();
403         this.pop.show();
404         this.update();
405         this.place();
406         
407         this.fireEvent('show', this, this.time);
408     },
409     
410     hide : function()
411     {
412         this.picker().hide();
413         this.pop.hide();
414         
415         this.fireEvent('hide', this, this.time);
416     },
417     
418     setTime : function()
419     {
420         this.hide();
421         this.setValue(this.time);
422         
423         this.fireEvent('select', this, this.time);
424         
425         
426     },
427
428     // return false when it fails
429     parseTime : function(value)
430     {
431         if(!value) {
432             return false;
433         }
434         if(value instanceof Date){
435             return value;
436         }
437         var v = Date.parseDate(value, 'H:i:s');
438
439         return (typeof(v) == 'undefined') ? false : v;
440     },
441
442     translateTime : function(time)
443     {
444         switch(this.language) {
445             case 'zh_CN':
446                 return new Intl.DateTimeFormat('zh-CN', {
447                     hour : 'numeric',
448                     minute : 'numeric',
449                     hour12 : true
450                 }).format(time);
451             default :
452                 return time.format(this.format);
453         }
454     },
455
456     setValue: function(v)
457     {
458         var t = this.parseTime(v);
459
460         if(!t) {
461             this.time = this.value = this.hiddenField.value =  '';
462             if(this.rendered){
463                 this.inputEl().dom.value = '';
464                 this.validate();
465             }
466             return;
467         }
468
469         this.value = this.hiddenField.value = t.dateFormat('H:i:s');
470
471         v = this.translateTime(t);
472
473         if(this.rendered){
474             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
475             this.validate();
476         }
477
478         this.time = t;
479
480         this.update();
481     },
482
483     setRawValue: function(v)
484     {
485         var t = this.parseTime(v);
486
487         if(!t) {
488             this.time = this.value = this.hiddenField.value =  '';
489             if(this.rendered){
490                 this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
491             }
492             return;
493         }
494
495         this.value = this.hiddenField.value = t.dateFormat('H:i:s');
496
497         v = this.translateTime(t);
498
499         if(this.rendered){
500             this.inputEl().dom.value = (v === null || v === undefined ? '' : v);
501         }
502
503         this.time = t;
504
505         this.update();
506     },
507
508     getValue: function()
509     {
510         return this.value;
511     },
512
513     getRawValue : function(){
514         return this.getValue();
515     },
516     
517     onMousedown: function(e){
518         e.stopPropagation();
519         e.preventDefault();
520     },
521     
522     onIncrementHours: function()
523     {
524         Roo.log('onIncrementHours');
525         this.time = this.time.add(Date.HOUR, 1);
526         this.update();
527         
528     },
529     
530     onDecrementHours: function()
531     {
532         Roo.log('onDecrementHours');
533         this.time = this.time.add(Date.HOUR, -1);
534         this.update();
535     },
536     
537     onIncrementMinutes: function()
538     {
539         Roo.log('onIncrementMinutes');
540         var minutesToAdd = Math.round((parseInt(this.time.format('i')) + this.minuteStep) / this.minuteStep) * this.minuteStep - parseInt(this.time.format('i'));
541         this.time = this.time.add(Date.MINUTE, minutesToAdd);
542         this.update();
543     },
544     
545     onDecrementMinutes: function()
546     {
547         Roo.log('onDecrementMinutes');
548         var minutesToSubtract = parseInt(this.time.format('i')) - Math.round((parseInt(this.time.format('i')) - this.minuteStep) / this.minuteStep) * this.minuteStep;
549         this.time = this.time.add(Date.MINUTE, -1 * minutesToSubtract);
550         this.update();
551     },
552     
553     onTogglePeriod: function()
554     {
555         Roo.log('onTogglePeriod');
556         this.time = this.time.add(Date.HOUR, 12);
557         this.update();
558     }
559     
560    
561 });
562 Roo.apply(Roo.bootstrap.form.TimeField,  {
563     okText : 'OK',
564     periodText : {
565         en : {
566             am : 'AM',
567             pm : 'PM'
568         },
569         zh_CN : {
570             am : '上午',
571             pm : '下午'
572         }
573     }
574 });
575
576 Roo.apply(Roo.bootstrap.form.TimeField,  {
577     template : {
578         tag: 'div',
579         cls: 'datepicker dropdown-menu',
580         cn: [
581             {
582                 tag: 'div',
583                 cls: 'datepicker-time',
584                 cn: [
585                 {
586                     tag: 'table',
587                     cls: 'table-condensed',
588                     cn:[
589                         {
590                             tag: 'tbody',
591                             cn: [
592                                 {
593                                     tag: 'tr',
594                                     cn: [
595                                     {
596                                         tag: 'td',
597                                         colspan: '7'
598                                     }
599                                     ]
600                                 }
601                             ]
602                         },
603                         {
604                             tag: 'tfoot',
605                             cn: [
606                                 {
607                                     tag: 'tr',
608                                     cn: [
609                                     {
610                                         tag: 'th',
611                                         colspan: '7',
612                                         cls: '',
613                                         cn: [
614                                             {
615                                                 tag: 'button',
616                                                 cls: 'btn btn-info ok',
617                                                 html: "OK" // this is overridden on construciton
618                                             }
619                                         ]
620                                     }
621                     
622                                     ]
623                                 }
624                             ]
625                         }
626                     ]
627                 }
628                 ]
629             }
630         ]
631     }
632 });
633
634  
635
636